Commit ae7e164f authored by peter@mysql.com's avatar peter@mysql.com

Merge mysql.com:/home/pz/mysql/mysql-4.1-root

into mysql.com:/home/pz/mysql/mysql-4.1
parents 31d702dd bdee968a
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "my_global.h"
#include "mysql.h" #include "mysql.h"
#define INSERT_QUERY "insert into test (name,num) values ('item %d', %d)" #define INSERT_QUERY "insert into test (name,num) values ('item %d', %d)"
......
...@@ -731,7 +731,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) ...@@ -731,7 +731,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
return 1; return 1;
} }
if (argv[1][0]) if (argv[1][0])
make_scrambled_password(crypted_pw,argv[1]); make_scrambled_password(crypted_pw,argv[1],0); /* New passwords only */
else else
crypted_pw[0]=0; /* No password */ crypted_pw[0]=0; /* No password */
sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw); sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "my_global.h"
#include "mysql.h" #include "mysql.h"
#define SELECT_QUERY "select name from test where num = %d" #define SELECT_QUERY "select name from test where num = %d"
......
...@@ -97,6 +97,7 @@ enum enum_server_command ...@@ -97,6 +97,7 @@ enum enum_server_command
#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ #define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */
#define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */ #define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */
#define CLIENT_PROTOCOL_41 16384 /* New 4.1 protocol */ #define CLIENT_PROTOCOL_41 16384 /* New 4.1 protocol */
#define CLIENT_SECURE_CONNECTION 32768 /* New 4.1 authentication */
#define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */ #define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */
#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */ #define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */
...@@ -279,7 +280,9 @@ extern unsigned long net_buffer_length; ...@@ -279,7 +280,9 @@ extern unsigned long net_buffer_length;
void randominit(struct rand_struct *,unsigned long seed1, void randominit(struct rand_struct *,unsigned long seed1,
unsigned long seed2); unsigned long seed2);
double rnd(struct rand_struct *); double rnd(struct rand_struct *);
void make_scrambled_password(char *to,const char *password); void make_scrambled_password(char *to,const char *password,my_bool force_old_scramble);
uint get_password_length(my_bool force_old_scramble);
uint8 get_password_version(const char* password);
void get_salt_from_password(unsigned long *res,const char *password); void get_salt_from_password(unsigned long *res,const char *password);
void make_password_from_salt(char *to, unsigned long *hash_res); void make_password_from_salt(char *to, unsigned long *hash_res);
char *scramble(char *to,const char *message,const char *password, char *scramble(char *to,const char *message,const char *password,
......
...@@ -60,7 +60,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ ...@@ -60,7 +60,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
my_compress.lo array.lo my_once.lo list.lo my_net.lo \ my_compress.lo array.lo my_once.lo list.lo my_net.lo \
charset.lo hash.lo mf_iocache.lo \ charset.lo hash.lo mf_iocache.lo \
mf_iocache2.lo my_seek.lo \ mf_iocache2.lo my_seek.lo \
my_pread.lo mf_cache.lo my_vsnprintf.lo md5.lo \ my_pread.lo mf_cache.lo my_vsnprintf.lo md5.lo sha1.lo\
my_getopt.lo my_gethostbyname.lo my_port.lo my_getopt.lo my_gethostbyname.lo my_port.lo
sqlobjects = net.lo sqlobjects = net.lo
......
/* Copyright (C) 2000 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* password checking routines */
/*****************************************************************************
The main idea is that no password are sent between client & server on
connection and that no password are saved in mysql in a decodable form.
On connection a random string is generated and sent to the client.
The client generates a new string with a random generator inited with
the hash values from the password and the sent string.
This 'check' string is sent to the server where it is compared with
a string generated from the stored hash_value of the password and the
random string.
The password is saved (in user.password) by using the PASSWORD() function in
mysql.
Example:
update user set password=PASSWORD("hello") where user="test"
This saves a hashed number as a string in the password field.
*****************************************************************************/
#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include "mysql.h"
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 */
#endif
rand_st->max_value= 0x3FFFFFFFL;
rand_st->max_value_dbl=(double) rand_st->max_value;
rand_st->seed1=seed1%rand_st->max_value ;
rand_st->seed2=seed2%rand_st->max_value;
}
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;
}
double rnd(struct rand_struct *rand_st)
{
rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
return (((double) rand_st->seed1)/rand_st->max_value_dbl);
}
void hash_password(ulong *result, const char *password)
{
register ulong nr=1345345333L, add=7, nr2=0x12345671L;
ulong tmp;
for (; *password ; password++)
{
if (*password == ' ' || *password == '\t')
continue; /* skipp space in password */
tmp= (ulong) (uchar) *password;
nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
nr2+=(nr2 << 8) ^ nr;
add+=tmp;
}
result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
result[1]=nr2 & (((ulong) 1L << 31) -1L);
return;
}
void make_scrambled_password(char *to,const char *password)
{
ulong hash_res[2];
hash_password(hash_res,password);
sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
}
static inline uint char_val(char X)
{
return (uint) (X >= '0' && X <= '9' ? X-'0' :
X >= 'A' && X <= 'Z' ? X-'A'+10 :
X-'a'+10);
}
/*
** This code assumes that len(password) is divideable with 8 and that
** res is big enough (2 in mysql)
*/
void get_salt_from_password(ulong *res,const char *password)
{
res[0]=res[1]=0;
if (password)
{
while (*password)
{
ulong val=0;
uint i;
for (i=0 ; i < 8 ; i++)
val=(val << 4)+char_val(*password++);
*res++=val;
}
}
return;
}
void make_password_from_salt(char *to, ulong *hash_res)
{
sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
}
/*
* Genererate a new message based on message and password
* The same thing is done in client and server and the results are checked.
*/
char *scramble(char *to,const char *message,const char *password,
my_bool old_ver)
{
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);
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 (*message++)
*to++= (char) (floor(rnd(&rand_st)*31)+64);
if (!old_ver)
{ /* Make it harder to break */
char extra=(char) (floor(rnd(&rand_st)*31));
while (to_start != to)
*(to_start++)^=extra;
}
}
*to=0;
return to;
}
my_bool check_scramble(const char *scrambled, const char *message,
ulong *hash_pass, my_bool old_ver)
{
struct rand_struct rand_st;
ulong hash_message[2];
char buff[16],*to,extra; /* Big enough for check */
const char *pos;
hash_password(hash_message,message);
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(rnd(&rand_st)*31)+64);
if (old_ver)
extra=0;
else
extra=(char) (floor(rnd(&rand_st)*31));
to=buff;
while (*scrambled)
{
if (*scrambled++ != (char) (*to++ ^ extra))
return 1; /* Wrong password */
}
return 0;
}
select length(encrypt('foo', 'ff')) <> 0; select length(encrypt('foo', 'ff')) <> 0;
length(encrypt('foo', 'ff')) <> 0 length(encrypt('foo', 'ff')) <> 0
1 1
select password('test'),length(encrypt('test')),encrypt('test','aa'); select old_password('test'),length(password("1")),length(encrypt('test')),encrypt('test','aa');
password('test') length(encrypt('test')) encrypt('test','aa') old_password('test') length(password("1")) length(encrypt('test')) encrypt('test','aa')
378b243e220ca493 13 aaqPiZY5xR5l. 378b243e220ca493 45 13 aaqPiZY5xR5l.
select length(encrypt('foo', 'ff')) <> 0; select length(encrypt('foo', 'ff')) <> 0;
--replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l. --replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l.
select password('test'),length(encrypt('test')),encrypt('test','aa'); select old_password('test'),length(password("1")),length(encrypt('test')),encrypt('test','aa');
...@@ -52,6 +52,13 @@ Item *create_func_ord(Item* a) ...@@ -52,6 +52,13 @@ Item *create_func_ord(Item* a)
return new Item_func_ord(a); return new Item_func_ord(a);
} }
Item *create_func_old_password(Item* a)
{
return new Item_func_old_password(a);
}
Item *create_func_asin(Item* a) Item *create_func_asin(Item* a)
{ {
return new Item_func_asin(a); return new Item_func_asin(a);
......
...@@ -66,6 +66,7 @@ Item *create_func_monthname(Item* a); ...@@ -66,6 +66,7 @@ Item *create_func_monthname(Item* a);
Item *create_func_nullif(Item* a, Item *b); Item *create_func_nullif(Item* a, Item *b);
Item *create_func_oct(Item *); Item *create_func_oct(Item *);
Item *create_func_ord(Item* a); Item *create_func_ord(Item* a);
Item *create_func_old_password(Item* a);
Item *create_func_period_add(Item* a, Item *b); Item *create_func_period_add(Item* a, Item *b);
Item *create_func_period_diff(Item* a, Item *b); Item *create_func_period_diff(Item* a, Item *b);
Item *create_func_pi(void); Item *create_func_pi(void);
......
...@@ -1273,11 +1273,25 @@ String *Item_func_password::val_str(String *str) ...@@ -1273,11 +1273,25 @@ String *Item_func_password::val_str(String *str)
return 0; return 0;
if (res->length() == 0) if (res->length() == 0)
return &empty_string; return &empty_string;
make_scrambled_password(tmp_value,res->c_ptr()); make_scrambled_password(tmp_value,res->c_ptr(),opt_old_passwords);
str->set(tmp_value,get_password_length(opt_old_passwords),res->charset());
return str;
}
String *Item_func_old_password::val_str(String *str)
{
String *res =args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
if (res->length() == 0)
return &empty_string;
make_scrambled_password(tmp_value,res->c_ptr(),1);
str->set(tmp_value,16,res->charset()); str->set(tmp_value,16,res->charset());
return str; return str;
} }
#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
String *Item_func_encrypt::val_str(String *str) String *Item_func_encrypt::val_str(String *str)
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
#pragma interface /* gcc class implementation */ #pragma interface /* gcc class implementation */
#endif #endif
extern my_bool opt_old_passwords; /* Need this variable for some functions */
class Item_str_func :public Item_func class Item_str_func :public Item_func
{ {
public: public:
...@@ -243,14 +246,27 @@ class Item_func_trim :public Item_str_func ...@@ -243,14 +246,27 @@ class Item_func_trim :public Item_str_func
class Item_func_password :public Item_str_func class Item_func_password :public Item_str_func
{ {
char tmp_value[17]; char tmp_value[64]; /* This should be enough for new password format */
public: public:
Item_func_password(Item *a) :Item_str_func(a) {} Item_func_password(Item *a) :Item_str_func(a) {}
String *val_str(String *); String *val_str(String *);
void fix_length_and_dec() { max_length = 16; } void fix_length_and_dec() { max_length = get_password_length(opt_old_passwords); }
const char *func_name() const { return "password"; } const char *func_name() const { return "password"; }
}; };
class Item_func_old_password :public Item_str_func
{
char tmp_value[16]; /* old password length */
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); }
const char *func_name() const { return "old_password"; }
};
class Item_func_des_encrypt :public Item_str_func class Item_func_des_encrypt :public Item_str_func
{ {
String tmp_value; String tmp_value;
......
...@@ -513,6 +513,7 @@ static SYMBOL sql_functions[] = { ...@@ -513,6 +513,7 @@ static SYMBOL sql_functions[] = {
{ "NUMPOINTS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numpoints)}, { "NUMPOINTS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numpoints)},
{ "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)}, { "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)},
{ "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)}, { "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)},
{ "OLD_PASSWORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_old_password)},
{ "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)}, { "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)},
{ "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)}, { "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)},
{ "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)}, { "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)},
......
...@@ -66,7 +66,8 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); ...@@ -66,7 +66,8 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
****************************************************************************/ ****************************************************************************/
#define ACL_CACHE_SIZE 256 #define ACL_CACHE_SIZE 256
#define HASH_PASSWORD_LENGTH 16 /* Password lengh for 4.1 version previous versions had 16 bytes password hash */
#define HASH_PASSWORD_LENGTH 45
#define HOST_CACHE_SIZE 128 #define HOST_CACHE_SIZE 128
#define MAX_ACCEPT_RETRY 10 // Test accept this many times #define MAX_ACCEPT_RETRY 10 // Test accept this many times
#define MAX_FIELDS_BEFORE_HASH 32 #define MAX_FIELDS_BEFORE_HASH 32
......
...@@ -278,7 +278,7 @@ static my_bool opt_noacl=0, opt_bootstrap=0, opt_myisam_log=0; ...@@ -278,7 +278,7 @@ static my_bool opt_noacl=0, opt_bootstrap=0, opt_myisam_log=0;
my_bool opt_safe_user_create = 0, opt_no_mix_types = 0; my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool opt_safe_show_db=0, lower_case_table_names, opt_old_rpl_compat; my_bool opt_safe_show_db=0, lower_case_table_names, opt_old_rpl_compat;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0; my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
my_bool opt_log_slave_updates= 0; my_bool opt_log_slave_updates= 0, opt_old_passwords=0;
volatile bool mqh_used = 0; volatile bool mqh_used = 0;
FILE *bootstrap_file=0; FILE *bootstrap_file=0;
...@@ -317,6 +317,7 @@ uint volatile thread_count=0, thread_running=0, kill_cached_threads=0, ...@@ -317,6 +317,7 @@ uint volatile thread_count=0, thread_running=0, kill_cached_threads=0,
ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL | ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL |
OPTION_BIN_LOG | OPTION_QUOTE_SHOW_CREATE ); OPTION_BIN_LOG | OPTION_QUOTE_SHOW_CREATE );
uint protocol_version=PROTOCOL_VERSION; uint protocol_version=PROTOCOL_VERSION;
uint connection_auth_flag=0; /* Supported authentication mode */
struct system_variables global_system_variables; struct system_variables global_system_variables;
struct system_variables max_system_variables; struct system_variables max_system_variables;
ulong keybuff_size,table_cache_size, ulong keybuff_size,table_cache_size,
...@@ -2894,7 +2895,8 @@ enum options { ...@@ -2894,7 +2895,8 @@ enum options {
OPT_INNODB_FORCE_RECOVERY, OPT_INNODB_FORCE_RECOVERY,
OPT_BDB_CACHE_SIZE, OPT_BDB_CACHE_SIZE,
OPT_BDB_LOG_BUFFER_SIZE, OPT_BDB_LOG_BUFFER_SIZE,
OPT_BDB_MAX_LOCK OPT_BDB_MAX_LOCK,
OPT_OLD_PASSWORDS
}; };
...@@ -3225,6 +3227,8 @@ struct my_option my_long_options[] = ...@@ -3225,6 +3227,8 @@ struct my_option my_long_options[] =
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).", {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 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 old clients)",
(gptr*) &opt_old_passwords, (gptr*) &opt_old_passwords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifndef TO_BE_DELETED #ifndef TO_BE_DELETED
{"safe-show-database", OPT_SAFE_SHOW_DB, {"safe-show-database", OPT_SAFE_SHOW_DB,
"Deprecated option; One should use GRANT SHOW DATABASES instead...", "Deprecated option; One should use GRANT SHOW DATABASES instead...",
......
...@@ -37,9 +37,18 @@ ...@@ -37,9 +37,18 @@
#include <my_global.h> #include <my_global.h>
#include <my_sys.h> #include <my_sys.h>
#include <m_string.h> #include <m_string.h>
#include <sha1.h>
#include "mysql.h" #include "mysql.h"
/* Character to use as version identifier for version 4.1 */
#define PVERSION41_CHAR '*'
void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2) void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
{ /* For mysql 3.21.# */ { /* For mysql 3.21.# */
#ifdef HAVE_purify #ifdef HAVE_purify
...@@ -84,13 +93,68 @@ void hash_password(ulong *result, const char *password) ...@@ -84,13 +93,68 @@ void hash_password(ulong *result, const char *password)
return; return;
} }
void make_scrambled_password(char *to,const char *password)
void make_scrambled_password(char *to,const char *password,my_bool force_old_scramble)
{ {
ulong hash_res[2]; ulong hash_res[2]; /* Used for pre 4.1 password hashing */
static uint salt=0; /* Salt for 4.1 version password */
unsigned char* slt=(unsigned char*)&salt;
SHA1_CONTEXT context;
uint8 digest[SHA1_HASH_SIZE];
if (force_old_scramble) /* Pre 4.1 password encryption */
{
hash_password(hash_res,password); hash_password(hash_res,password);
sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]); sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
}
else /* New password 4.1 password scrambling */
{
to[0]=PVERSION41_CHAR; /* New passwords have version prefix */
/* We do not need too strong salt generation so this should be enough */
salt+=getpid()+time(NULL)+0x01010101;
/* Use only 2 first bytes from it */
sprintf(&(to[1]),"%02x%02x",slt[0],slt[1]);
sha1_reset(&context);
/* Use Salt for Hash */
sha1_input(&context,(uint8*)&salt,2);
for (; *password ; password++)
{
if (*password == ' ' || *password == '\t')
continue;/* skip space in password */
sha1_input(&context,(int8*)&password[0],1);
}
sha1_result(&context,digest);
/* Hash one more time */
sha1_reset(&context);
sha1_input(&context,digest,SHA1_HASH_SIZE);
sha1_result(&context,digest);
/* 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]);
}
}
uint get_password_length(my_bool force_old_scramble)
{
if (force_old_scramble)
return 16;
else return SHA1_HASH_SIZE*2+4+1;
}
uint8 get_password_version(const char* password)
{
if (password==NULL) return 0;
if (password[0]==PVERSION41_CHAR) return PVERSION41_CHAR;
return 0;
} }
inline uint char_val(char X) inline uint char_val(char X)
{ {
return (uint) (X >= '0' && X <= '9' ? X-'0' : return (uint) (X >= '0' && X <= '9' ? X-'0' :
...@@ -99,15 +163,27 @@ inline uint char_val(char X) ...@@ -99,15 +163,27 @@ inline uint char_val(char X)
} }
/* /*
** This code assumes that len(password) is divideable with 8 and that ** This code detects new version password by leading char.
** res is big enough (2 in mysql) ** Old password has to be divisible by 8 length
** do not forget to increase array length if you need longer passwords
*/ */
void get_salt_from_password(ulong *res,const char *password) void get_salt_from_password(ulong *res,const char *password)
{ {
res[0]=res[1]=0; bzero(res,5*sizeof(res[0]));
if (password) if (password)
{ {
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;
}
while (*password) while (*password)
{ {
ulong val=0; ulong val=0;
...@@ -122,6 +198,7 @@ void get_salt_from_password(ulong *res,const char *password) ...@@ -122,6 +198,7 @@ void get_salt_from_password(ulong *res,const char *password)
void make_password_from_salt(char *to, ulong *hash_res) void make_password_from_salt(char *to, ulong *hash_res)
{ {
// warning this does not work for new passwords yet
sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]); sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
} }
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include <assert.h> #include <assert.h>
#include <stdarg.h> #include <stdarg.h>
extern uint connection_auth_flag;
struct acl_host_and_ip struct acl_host_and_ip
{ {
char *hostname; char *hostname;
...@@ -63,7 +65,8 @@ class ACL_USER :public ACL_ACCESS ...@@ -63,7 +65,8 @@ class ACL_USER :public ACL_ACCESS
uint hostname_length; uint hostname_length;
USER_RESOURCES user_resource; USER_RESOURCES user_resource;
char *user,*password; char *user,*password;
ulong salt[2]; ulong salt[6]; // New password has longer length
uint8 pversion; // password version
enum SSL_type ssl_type; enum SSL_type ssl_type;
const char *ssl_cipher, *x509_issuer, *x509_subject; const char *ssl_cipher, *x509_issuer, *x509_subject;
}; };
...@@ -142,7 +145,11 @@ my_bool acl_init(bool dont_read_acl_tables) ...@@ -142,7 +145,11 @@ my_bool acl_init(bool dont_read_acl_tables)
(hash_get_key) acl_entry_get_key, (hash_get_key) acl_entry_get_key,
(void (*)(void*)) free); (void (*)(void*)) free);
if (dont_read_acl_tables) if (dont_read_acl_tables)
{
/* If we do not read tables use old handshake to make it quick for all clients */
connection_auth_flag=CLIENT_LONG_PASSWORD;
DBUG_RETURN(0); /* purecov: tested */ DBUG_RETURN(0); /* purecov: tested */
}
/* /*
To be able to run this from boot, we allocate a temporary THD To be able to run this from boot, we allocate a temporary THD
...@@ -217,6 +224,7 @@ my_bool acl_init(bool dont_read_acl_tables) ...@@ -217,6 +224,7 @@ my_bool acl_init(bool dont_read_acl_tables)
DBUG_PRINT("info",("user table fields: %d",table->fields)); DBUG_PRINT("info",("user table fields: %d",table->fields));
allow_all_hosts=0; allow_all_hosts=0;
connection_auth_flag=0; /* Reset flag as we're rereading the table */
while (!(read_record_info.read_record(&read_record_info))) while (!(read_record_info.read_record(&read_record_info)))
{ {
ACL_USER user; ACL_USER user;
...@@ -231,7 +239,7 @@ my_bool acl_init(bool dont_read_acl_tables) ...@@ -231,7 +239,7 @@ my_bool acl_init(bool dont_read_acl_tables)
"Found old style password for user '%s'. Ignoring user. (You may want to restart mysqld using --old-protocol)", "Found old style password for user '%s'. Ignoring user. (You may want to restart mysqld using --old-protocol)",
user.user ? user.user : ""); /* purecov: tested */ user.user ? user.user : ""); /* purecov: tested */
} }
else if (length % 8) // This holds true for passwords else if (length % 8 && length!=45) // This holds true for passwords
{ {
sql_print_error( sql_print_error(
"Found invalid password for user: '%s@%s'; Ignoring user", "Found invalid password for user: '%s@%s'; Ignoring user",
...@@ -240,6 +248,19 @@ my_bool acl_init(bool dont_read_acl_tables) ...@@ -240,6 +248,19 @@ my_bool acl_init(bool dont_read_acl_tables)
continue; /* purecov: tested */ continue; /* purecov: tested */
} }
get_salt_from_password(user.salt,user.password); get_salt_from_password(user.salt,user.password);
user.pversion=get_password_version(user.password);
/*
We check the version of passwords in database. If no old passwords found we can force new handshake
if there are only old password we will force new handshake. In case of both types of passwords
found we will perform 2 stage authentication.
*/
if (user.password && user.password[0]!=0) /* empty passwords are not counted */
{
if (user.pversion)
connection_auth_flag|=CLIENT_SECURE_CONNECTION;
else
connection_auth_flag|=CLIENT_LONG_PASSWORD;
}
user.access=get_access(table,3) & GLOBAL_ACLS; user.access=get_access(table,3) & GLOBAL_ACLS;
user.sort=get_sort(2,user.host.hostname,user.user); user.sort=get_sort(2,user.host.hostname,user.user);
user.hostname_length= (user.host.hostname ? user.hostname_length= (user.host.hostname ?
...@@ -298,6 +319,17 @@ my_bool acl_init(bool dont_read_acl_tables) ...@@ -298,6 +319,17 @@ my_bool acl_init(bool dont_read_acl_tables)
end_read_record(&read_record_info); end_read_record(&read_record_info);
freeze_size(&acl_users); freeze_size(&acl_users);
/*
If database is empty or has no passwords use new connection protocol
unless we're running with --old-passwords option
*/
if (!connection_auth_flag)
{
if(!opt_old_passwords)
connection_auth_flag=CLIENT_SECURE_CONNECTION;
else connection_auth_flag=CLIENT_LONG_PASSWORD;
}
printf("Set flag after read: %d\n",connection_auth_flag);
init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0); init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0);
VOID(my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100)); VOID(my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100));
while (!(read_record_info.read_record(&read_record_info))) while (!(read_record_info.read_record(&read_record_info)))
...@@ -671,6 +703,13 @@ static void acl_update_user(const char *user, const char *host, ...@@ -671,6 +703,13 @@ static void acl_update_user(const char *user, const char *host,
{ {
acl_user->password=(char*) ""; // Just point at something acl_user->password=(char*) ""; // Just point at something
get_salt_from_password(acl_user->salt,password); get_salt_from_password(acl_user->salt,password);
acl_user->pversion=get_password_version(acl_user->password);
// We should allow connection with authentication method matching password
if (acl_user->pversion)
connection_auth_flag|=CLIENT_SECURE_CONNECTION;
else
connection_auth_flag|=CLIENT_LONG_PASSWORD;
printf("Debug: flag set to %d\n",connection_auth_flag);
} }
} }
break; break;
...@@ -706,6 +745,7 @@ static void acl_insert_user(const char *user, const char *host, ...@@ -706,6 +745,7 @@ static void acl_insert_user(const char *user, const char *host,
{ {
acl_user.password=(char*) ""; // Just point at something acl_user.password=(char*) ""; // Just point at something
get_salt_from_password(acl_user.salt,password); get_salt_from_password(acl_user.salt,password);
acl_user.pversion=get_password_version(acl_user.password);
} }
VOID(push_dynamic(&acl_users,(gptr) &acl_user)); VOID(push_dynamic(&acl_users,(gptr) &acl_user));
...@@ -1052,8 +1092,10 @@ bool change_password(THD *thd, const char *host, const char *user, ...@@ -1052,8 +1092,10 @@ bool change_password(THD *thd, const char *host, const char *user,
if (check_change_password(thd, host, user)) if (check_change_password(thd, host, user))
DBUG_RETURN(1); DBUG_RETURN(1);
/* password should always be 0 or 16 chars; simple hack to avoid cracking */ /* password should always be 0,16 or 45 chars; simple hack to avoid cracking */
length=(uint) strlen(new_password); length=(uint) strlen(new_password);
if (length!=45)
new_password[length & 16]=0; new_password[length & 16]=0;
VOID(pthread_mutex_lock(&acl_cache->lock)); VOID(pthread_mutex_lock(&acl_cache->lock));
...@@ -1074,14 +1116,23 @@ bool change_password(THD *thd, const char *host, const char *user, ...@@ -1074,14 +1116,23 @@ bool change_password(THD *thd, const char *host, const char *user,
DBUG_RETURN(1); /* purecov: deadcode */ DBUG_RETURN(1); /* purecov: deadcode */
} }
get_salt_from_password(acl_user->salt,new_password); get_salt_from_password(acl_user->salt,new_password);
acl_user->pversion=get_password_version(new_password);
if (!new_password[0]) if (!new_password[0])
acl_user->password=0; acl_user->password=0;
else else
{
acl_user->password=(char*) ""; // Point at something acl_user->password=(char*) ""; // Point at something
/* Adjust global connection options depending of client password*/
if (acl_user->pversion)
connection_auth_flag|=CLIENT_SECURE_CONNECTION;
else
connection_auth_flag|=CLIENT_LONG_PASSWORD;
}
acl_cache->clear(1); // Clear locked hostname cache acl_cache->clear(1); // Clear locked hostname cache
VOID(pthread_mutex_unlock(&acl_cache->lock)); VOID(pthread_mutex_unlock(&acl_cache->lock));
char buff[460]; char buff[512]; /* Extend with extended password length*/
ulong query_length= ulong query_length=
my_sprintf(buff, my_sprintf(buff,
(buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"", (buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"",
......
...@@ -3650,7 +3650,7 @@ text_or_password: ...@@ -3650,7 +3650,7 @@ text_or_password:
else else
{ {
char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1); char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1);
make_scrambled_password(buff,$3.str); make_scrambled_password(buff,$3.str,opt_old_passwords);
$$=buff; $$=buff;
} }
} }
...@@ -3941,7 +3941,7 @@ grant_user: ...@@ -3941,7 +3941,7 @@ grant_user:
char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1); char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1);
if (buff) if (buff)
{ {
make_scrambled_password(buff,$4.str); make_scrambled_password(buff,$4.str,opt_old_passwords);
$1->password.str=buff; $1->password.str=buff;
$1->password.length=HASH_PASSWORD_LENGTH; $1->password.length=HASH_PASSWORD_LENGTH;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment