Commit 35ccfd0b authored by peter@mysql.com's avatar peter@mysql.com

SCRUM: Main change for Secure connection handling. Still needs some more coding. Commit

done for merge with newer version of code.
parent 96131759
...@@ -87,7 +87,7 @@ enum commands { ...@@ -87,7 +87,7 @@ enum commands {
ADMIN_FLUSH_HOSTS, ADMIN_FLUSH_TABLES, ADMIN_PASSWORD, ADMIN_FLUSH_HOSTS, ADMIN_FLUSH_TABLES, ADMIN_PASSWORD,
ADMIN_PING, ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS, ADMIN_PING, ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS,
ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE, ADMIN_STOP_SLAVE, ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE, ADMIN_STOP_SLAVE,
ADMIN_FLUSH_THREADS ADMIN_FLUSH_THREADS, ADMIN_OLD_PASSWORD
}; };
static const char *command_names[]= { static const char *command_names[]= {
"create", "drop", "shutdown", "create", "drop", "shutdown",
...@@ -97,7 +97,7 @@ static const char *command_names[]= { ...@@ -97,7 +97,7 @@ static const char *command_names[]= {
"flush-hosts", "flush-tables", "password", "flush-hosts", "flush-tables", "password",
"ping", "extended-status", "flush-status", "ping", "extended-status", "flush-status",
"flush-privileges", "start-slave", "stop-slave", "flush-privileges", "start-slave", "stop-slave",
"flush-threads", "flush-threads","old-password",
NullS NullS
}; };
...@@ -419,7 +419,8 @@ static my_bool sql_connect(MYSQL *mysql, uint wait) ...@@ -419,7 +419,8 @@ static my_bool sql_connect(MYSQL *mysql, uint wait)
static int execute_commands(MYSQL *mysql,int argc, char **argv) static int execute_commands(MYSQL *mysql,int argc, char **argv)
{ {
const char *status; const char *status;
struct rand_struct rand_st;
for (; argc > 0 ; argv++,argc--) for (; argc > 0 ; argv++,argc--)
{ {
switch (find_type(argv[0],&command_typelib,2)) { switch (find_type(argv[0],&command_typelib,2)) {
...@@ -721,17 +722,23 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) ...@@ -721,17 +722,23 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
} }
break; break;
} }
case ADMIN_OLD_PASSWORD:
case ADMIN_PASSWORD: case ADMIN_PASSWORD:
{ {
char buff[128],crypted_pw[33]; char buff[128],crypted_pw[64];
time_t start_time;
/* Do initialization the same way as we do in mysqld */
start_time=time((time_t*) 0);
randominit(&rand_st,(ulong) start_time,(ulong) start_time/2);
if (argc < 2) if (argc < 2)
{ {
my_printf_error(0,"Too few arguments to change password",MYF(ME_BELL)); my_printf_error(0,"Too few arguments to change password",MYF(ME_BELL));
return 1; return 1;
} }
if (argv[1][0]) if (argv[1][0])
make_scrambled_password(crypted_pw,argv[1],0); /* New passwords only */ make_scrambled_password(crypted_pw,argv[1],(find_type(argv[0],&command_typelib,2)
==ADMIN_OLD_PASSWORD),&rand_st);
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);
...@@ -836,7 +843,8 @@ static void usage(void) ...@@ -836,7 +843,8 @@ static void usage(void)
kill id,id,... Kill mysql threads"); kill id,id,... Kill mysql threads");
#if MYSQL_VERSION_ID >= 32200 #if MYSQL_VERSION_ID >= 32200
puts("\ puts("\
password new-password Change old password to new-password"); password new-password Change old password to new-password, MySQL 4.1 hashing.\n\
old-password new-password Change old password to new-password in old format.\n");
#endif #endif
puts("\ puts("\
ping Check if mysqld is alive\n\ ping Check if mysqld is alive\n\
......
...@@ -181,7 +181,7 @@ typedef struct st_mysql ...@@ -181,7 +181,7 @@ typedef struct st_mysql
enum mysql_status status; enum mysql_status status;
my_bool free_me; /* If free in mysql_close */ my_bool free_me; /* If free in mysql_close */
my_bool reconnect; /* set to 1 if automatic reconnect */ my_bool reconnect; /* set to 1 if automatic reconnect */
char scramble_buff[9]; char scramble_buff[21]; /* New protocol requires longer scramble*/
/* /*
Set if this is the original connection, not a master or a slave we have Set if this is the original connection, not a master or a slave we have
......
...@@ -280,10 +280,17 @@ extern unsigned long net_buffer_length; ...@@ -280,10 +280,17 @@ 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,my_bool force_old_scramble); void make_scrambled_password(char *to,const char *password,my_bool force_old_scramble,struct rand_struct *rand_st);
uint get_password_length(my_bool force_old_scramble); uint get_password_length(my_bool force_old_scramble);
uint8 get_password_version(const char* password); uint8 get_password_version(const char* password);
void create_random_string(int length,struct rand_struct *rand_st,char* target);
my_bool validate_password(const char* password, const char* message, ulong* salt);
void password_hash_stage1(char *to, const char *password);
void password_hash_stage2(char *to,const char *salt);
void password_crypt(const char* from,char* to, const char* password,int length);
void get_hash_and_password(ulong* salt, uint8 pversion,char* hash, unsigned char* bin_password);
void get_salt_from_password(unsigned long *res,const char *password); void get_salt_from_password(unsigned long *res,const char *password);
void create_key_from_old_password(const char* password,char* key);
void make_password_from_salt(char *to, unsigned long *hash_res, uint8 password_version); void make_password_from_salt(char *to, unsigned long *hash_res, uint8 password_version);
char *scramble(char *to,const char *message,const char *password, char *scramble(char *to,const char *message,const char *password,
my_bool old_ver); my_bool old_ver);
......
...@@ -67,7 +67,7 @@ ulong net_write_timeout= NET_WRITE_TIMEOUT; ...@@ -67,7 +67,7 @@ ulong net_write_timeout= NET_WRITE_TIMEOUT;
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG \ #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG \
| CLIENT_LOCAL_FILES | CLIENT_TRANSACTIONS \ | CLIENT_LOCAL_FILES | CLIENT_TRANSACTIONS \
| CLIENT_PROTOCOL_41) | CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION)
#ifdef __WIN__ #ifdef __WIN__
...@@ -1585,6 +1585,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, ...@@ -1585,6 +1585,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
{ {
char buff[NAME_LEN+USERNAME_LENGTH+100],charset_name_buff[16]; char buff[NAME_LEN+USERNAME_LENGTH+100],charset_name_buff[16];
char *end,*host_info,*charset_name; char *end,*host_info,*charset_name;
char password_hash[20]; /* Used for tmp storage of stage1 hash */
my_socket sock; my_socket sock;
uint32 ip_addr; uint32 ip_addr;
struct sockaddr_in sock_addr; struct sockaddr_in sock_addr;
...@@ -1789,7 +1790,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, ...@@ -1789,7 +1790,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
if ((pkt_length=net_safe_read(mysql)) == packet_error) if ((pkt_length=net_safe_read(mysql)) == packet_error)
goto error; goto error;
/* Check if version of protocoll matches current one */ /* Check if version of protocol matches current one */
mysql->protocol_version= net->read_pos[0]; mysql->protocol_version= net->read_pos[0];
DBUG_DUMP("packet",(char*) net->read_pos,10); DBUG_DUMP("packet",(char*) net->read_pos,10);
...@@ -1855,7 +1856,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, ...@@ -1855,7 +1856,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
} }
goto error; goto error;
} }
/* Save connection information */ /* Save connection information */
if (!user) user=""; if (!user) user="";
if (!passwd) passwd=""; if (!passwd) passwd="";
...@@ -1962,32 +1963,105 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, ...@@ -1962,32 +1963,105 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
DBUG_PRINT("info",("Server version = '%s' capabilites: %ld status: %d client_flag: %d", DBUG_PRINT("info",("Server version = '%s' capabilites: %ld status: %d client_flag: %d",
mysql->server_version,mysql->server_capabilities, mysql->server_version,mysql->server_capabilities,
mysql->server_status, client_flag)); mysql->server_status, client_flag));
int3store(buff+2,max_allowed_packet); int3store(buff+2,max_allowed_packet);
if (user && user[0]) if (user && user[0])
strmake(buff+5,user,32); /* Max user name */ strmake(buff+5,user,32); /* Max user name */
else else
read_user_name((char*) buff+5); read_user_name((char*) buff+5);
/* We have to handle different version of handshake here */
#ifdef _CUSTOMCONFIG_ #ifdef _CUSTOMCONFIG_
#include "_cust_libmysql.h"; #include "_cust_libmysql.h";
#endif #endif
DBUG_PRINT("info",("user: %s",buff+5)); DBUG_PRINT("info",("user: %s",buff+5));
end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd, /*
(my_bool) (mysql->protocol_version == 9)); We always start with old type handshake the only difference is message sent
If server handles secure connection type we'll not send the real scramble
*/
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
if (passwd[0])
{
/* Use something for not empty password not to match it against empty one */
end=scramble(strend(buff+5)+1, mysql->scramble_buff,"~MySQL#!",
(my_bool) (mysql->protocol_version == 9));
}
else /* For empty password*/
{
end=strend(buff+5)+1;
*end=0; /* Store zero length scramble */
}
}
/* Real scramble is sent only for servers. This is to be blocked by option */
else
end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
/* Add database if needed */
if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB)) if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{ {
end=strmake(end+1,db,NAME_LEN); end=strmake(end+1,db,NAME_LEN);
mysql->db=my_strdup(db,MYF(MY_WME)); mysql->db=my_strdup(db,MYF(MY_WME));
db=0; db=0;
} }
/* Write authentication package */
if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net)) if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net))
{ {
net->last_errno= CR_SERVER_LOST; net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno)); strmov(net->last_error,ER(net->last_errno));
goto error; goto error;
} }
if (net_safe_read(mysql) == packet_error)
/* We shall only query sever if it expect us to do so */
if ( (pkt_length=net_safe_read(mysql)) == packet_error)
goto error; goto error;
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
/* This should basically always happen with new server unless empty password */
if (pkt_length==24) /* We have new hash back */
{
/* Old passwords will have zero at the first byte of hash */
if (net->read_pos[0])
{
/* Build full password hash as it is required to decode scramble */
password_hash_stage1(buff, passwd);
/* Store copy as we'll need it later */
memcpy(password_hash,buff,20);
/* Finally hash complete password using hash we got from server */
password_hash_stage2(password_hash,net->read_pos);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt(net->read_pos+4,mysql->scramble_buff,password_hash,20);
mysql->scramble_buff[20]=0;
/* Encode scramble with password. Recycle buffer */
password_crypt(mysql->scramble_buff,buff,buff,20);
}
else
{
/* Create password to decode scramble */
create_key_from_old_password(passwd,password_hash);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt(net->read_pos+4,mysql->scramble_buff,password_hash,20);
mysql->scramble_buff[20]=0;
/* Finally scramble decoded scramble with password */
scramble(buff, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
}
/* Write second package of authentication */
if (my_net_write(net,buff,20) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Read What server thinks about out new auth message report */
if (net_safe_read(mysql) == packet_error)
goto error;
}
}
/* End of authentication part of handshake */
if (client_flag & CLIENT_COMPRESS) /* We will use compression */ if (client_flag & CLIENT_COMPRESS) /* We will use compression */
net->compress=1; net->compress=1;
if (db && mysql_select_db(mysql,db)) if (db && mysql_select_db(mysql,db))
......
...@@ -123,7 +123,7 @@ then ...@@ -123,7 +123,7 @@ then
c_u="$c_u CREATE TABLE user (" c_u="$c_u CREATE TABLE user ("
c_u="$c_u Host char(60) binary DEFAULT '' NOT NULL," c_u="$c_u Host char(60) binary DEFAULT '' NOT NULL,"
c_u="$c_u User char(16) binary DEFAULT '' NOT NULL," c_u="$c_u User char(16) binary DEFAULT '' NOT NULL,"
c_u="$c_u Password char(16) binary DEFAULT '' NOT NULL," c_u="$c_u Password char(45) binary DEFAULT '' NOT NULL,"
c_u="$c_u Select_priv enum('N','Y') DEFAULT 'N' NOT NULL," c_u="$c_u Select_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
c_u="$c_u Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL," c_u="$c_u Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
c_u="$c_u Update_priv enum('N','Y') DEFAULT 'N' NOT NULL," c_u="$c_u Update_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
......
...@@ -5,7 +5,7 @@ master-bin.000001 ...@@ -5,7 +5,7 @@ master-bin.000001
4 4
127.0.0.1 127.0.0.1
replicate replicate
aaaaaaaaaaaaaaabthispartofthepasswordisnotused aaaaaaaaaaaaaaab
$MASTER_MYPORT $MASTER_MYPORT
1 1
0 0
......
...@@ -170,6 +170,7 @@ fi ...@@ -170,6 +170,7 @@ fi
@bindir@/mysql -f --user=root --password="$root_password" --host="$host" mysql <<END_OF_DATA @bindir@/mysql -f --user=root --password="$root_password" --host="$host" mysql <<END_OF_DATA
alter table user alter table user
change password password char(45) not null,
add max_questions int(11) NOT NULL AFTER x509_subject, add max_questions int(11) NOT NULL AFTER x509_subject,
add max_updates int(11) unsigned NOT NULL AFTER max_questions, add max_updates int(11) unsigned NOT NULL AFTER max_questions,
add max_connections int(11) unsigned NOT NULL AFTER max_updates; add max_connections int(11) unsigned NOT NULL AFTER max_updates;
......
...@@ -213,7 +213,7 @@ then ...@@ -213,7 +213,7 @@ then
c_u="$c_u CREATE TABLE user (" c_u="$c_u CREATE TABLE user ("
c_u="$c_u Host char(60) binary DEFAULT '' NOT NULL," c_u="$c_u Host char(60) binary DEFAULT '' NOT NULL,"
c_u="$c_u User char(16) binary DEFAULT '' NOT NULL," c_u="$c_u User char(16) binary DEFAULT '' NOT NULL,"
c_u="$c_u Password char(16) binary DEFAULT '' NOT NULL," c_u="$c_u Password char(45) binary DEFAULT '' NOT NULL,"
c_u="$c_u Select_priv enum('N','Y') DEFAULT 'N' NOT NULL," c_u="$c_u Select_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
c_u="$c_u Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL," c_u="$c_u Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
c_u="$c_u Update_priv enum('N','Y') DEFAULT 'N' NOT NULL," c_u="$c_u Update_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
......
...@@ -1279,7 +1279,7 @@ String *Item_func_password::val_str(String *str) ...@@ -1279,7 +1279,7 @@ 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(),opt_old_passwords); make_scrambled_password(tmp_value,res->c_ptr(),opt_old_passwords,&current_thd->rand);
str->set(tmp_value,get_password_length(opt_old_passwords),res->charset()); str->set(tmp_value,get_password_length(opt_old_passwords),res->charset());
return str; return str;
} }
...@@ -1291,7 +1291,7 @@ String *Item_func_old_password::val_str(String *str) ...@@ -1291,7 +1291,7 @@ String *Item_func_old_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(),1); make_scrambled_password(tmp_value,res->c_ptr(),1,&current_thd->rand);
str->set(tmp_value,16,res->charset()); str->set(tmp_value,16,res->charset());
return str; return str;
} }
......
...@@ -87,7 +87,9 @@ static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, ...@@ -87,7 +87,9 @@ static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES) #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \
CLIENT_LOCAL_FILES | CLIENT_SECURE_CONNECTION)
#if defined(MSDOS) || defined(__WIN__) #if defined(MSDOS) || defined(__WIN__)
#define perror(A) #define perror(A)
...@@ -488,6 +490,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user, ...@@ -488,6 +490,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
uint net_read_timeout) uint net_read_timeout)
{ {
char buff[NAME_LEN+USERNAME_LENGTH+100],*end,*host_info; char buff[NAME_LEN+USERNAME_LENGTH+100],*end,*host_info;
char password_hash[20];
my_socket sock; my_socket sock;
ulong ip_addr; ulong ip_addr;
struct sockaddr_in sock_addr; struct sockaddr_in sock_addr;
...@@ -510,7 +513,6 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user, ...@@ -510,7 +513,6 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
user ? user : "(Null)", user ? user : "(Null)",
net_read_timeout, net_read_timeout,
(uint) slave_net_timeout)); (uint) slave_net_timeout));
net->vio = 0; /* If something goes wrong */ net->vio = 0; /* If something goes wrong */
mysql->charset=default_charset_info; /* Set character set */ mysql->charset=default_charset_info; /* Set character set */
if (!port) if (!port)
...@@ -799,22 +801,96 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user, ...@@ -799,22 +801,96 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
} }
DBUG_PRINT("info",("user: %s",buff+5)); DBUG_PRINT("info",("user: %s",buff+5));
end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9)); /*
if (db) We always start with old type handshake the only difference is message sent
If server handles secure connection type we'll not send the real scramble
*/
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
if (passwd[0])
{
/* Use something for not empty password not to match it against empty one */
end=scramble(strend(buff+5)+1, mysql->scramble_buff,"~MySQL#!",
(my_bool) (mysql->protocol_version == 9));
}
else /* For empty password*/
{
end=strend(buff+5)+1;
*end=0; /* Store zero length scramble */
}
}
/* Real scramble is sent only for old servers. This is to be blocked by option */
else
end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
/* Add database if needed */
if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{ {
end=strmake(end+1,db,NAME_LEN); end=strmake(end+1,db,NAME_LEN);
mysql->db=my_strdup(db,MYF(MY_WME)); mysql->db=my_strdup(db,MYF(MY_WME));
db=0; db=0;
} }
/* Write authentication package */
if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net)) if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net))
{ {
net->last_errno= CR_SERVER_LOST; net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno)); strmov(net->last_error,ER(net->last_errno));
goto error; goto error;
} }
if (mc_net_safe_read(mysql) == packet_error)
/* We shall only query sever if it expect us to do so */
if ( (pkt_length=mc_net_safe_read(mysql)) == packet_error)
goto error; goto error;
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
{
/* This should basically always happen with new server unless empty password */
if (pkt_length==24) /* We have new hash back */
{
/* Old passwords will have zero at the first byte of hash */
if (net->read_pos[0])
{
/* Build full password hash as it is required to decode scramble */
password_hash_stage1(buff, passwd);
/* Store copy as we'll need it later */
memcpy(password_hash,buff,20);
/* Finally hash complete password using hash we got from server */
password_hash_stage2(password_hash,(char*)net->read_pos);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((char*)net->read_pos+4,mysql->scramble_buff,password_hash,20);
mysql->scramble_buff[20]=0;
/* Encode scramble with password. Recycle buffer */
password_crypt(mysql->scramble_buff,buff,buff,20);
}
else
{
/* Create password to decode scramble */
create_key_from_old_password(passwd,password_hash);
/* Decypt and store scramble 4 = hash for stage2 */
password_crypt((char*)net->read_pos+4,mysql->scramble_buff,password_hash,20);
mysql->scramble_buff[20]=0;
/* Finally scramble decoded scramble with password */
scramble(buff, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
}
/* Write second package of authentication */
if (my_net_write(net,buff,20) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Read What server thinks about out new auth message report */
if (mc_net_safe_read(mysql) == packet_error)
goto error;
}
}
/* End of authentication part of handshake */
if (client_flag & CLIENT_COMPRESS) /* We will use compression */ if (client_flag & CLIENT_COMPRESS) /* We will use compression */
net->compress=1; net->compress=1;
DBUG_PRINT("exit",("Mysql handler: %lx",mysql)); DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
......
...@@ -317,7 +317,6 @@ uint volatile thread_count=0, thread_running=0, kill_cached_threads=0, ...@@ -317,7 +317,6 @@ 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,
......
This diff is collapsed.
This diff is collapsed.
...@@ -88,7 +88,7 @@ ulong acl_get(const char *host, const char *ip, const char *bin_ip, ...@@ -88,7 +88,7 @@ ulong acl_get(const char *host, const char *ip, const char *bin_ip,
const char *user, const char *db); const char *user, const char *db);
ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *scramble,char **priv_user, const char *password,const char *scramble,char **priv_user,
bool old_ver, USER_RESOURCES *max); bool old_ver, USER_RESOURCES *max,char* prepared_scramble, int stage);
bool acl_check_host(const char *host, const char *ip); bool acl_check_host(const char *host, const char *ip);
bool check_change_password(THD *thd, const char *host, const char *user); bool check_change_password(THD *thd, const char *host, const char *user);
bool change_password(THD *thd, const char *host, const char *user, bool change_password(THD *thd, const char *host, const char *user,
......
...@@ -496,7 +496,7 @@ class THD :public ilink { ...@@ -496,7 +496,7 @@ class THD :public ilink {
uint select_number; //number of select (used for EXPLAIN) uint select_number; //number of select (used for EXPLAIN)
/* variables.transaction_isolation is reset to this after each commit */ /* variables.transaction_isolation is reset to this after each commit */
enum_tx_isolation session_tx_isolation; enum_tx_isolation session_tx_isolation;
char scramble[9]; char scramble[21]; // extend scramble to handle new auth
uint8 query_cache_type; // type of query cache processing uint8 query_cache_type; // type of query cache processing
bool slave_thread; bool slave_thread;
bool set_query_id,locked,count_cuted_fields,some_tables_deleted; bool set_query_id,locked,count_cuted_fields,some_tables_deleted;
......
...@@ -45,13 +45,13 @@ ...@@ -45,13 +45,13 @@
#define MIN_HANDSHAKE_SIZE 6 #define MIN_HANDSHAKE_SIZE 6
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
#define SCRAMBLE_LENGTH 8 #define SCRAMBLE_LENGTH 8
#define SCRAMBLE41_LENGTH 20
#define MEM_ROOT_BLOCK_SIZE 8192 #define MEM_ROOT_BLOCK_SIZE 8192
#define MEM_ROOT_PREALLOC 8192 #define MEM_ROOT_PREALLOC 8192
#define TRANS_MEM_ROOT_BLOCK_SIZE 4096 #define TRANS_MEM_ROOT_BLOCK_SIZE 4096
#define TRANS_MEM_ROOT_PREALLOC 4096 #define TRANS_MEM_ROOT_PREALLOC 4096
extern uint connection_auth_flag;
extern int yyparse(void); extern int yyparse(void);
extern "C" pthread_mutex_t THR_LOCK_keycache; extern "C" pthread_mutex_t THR_LOCK_keycache;
...@@ -180,40 +180,51 @@ static int get_or_create_user_conn(THD *thd, const char *user, ...@@ -180,40 +180,51 @@ static int get_or_create_user_conn(THD *thd, const char *user,
*/ */
static bool check_user(THD *thd,enum_server_command command, const char *user, static bool check_user(THD *thd,enum_server_command command, const char *user,
const char *passwd, const char *db, bool check_count) const char *passwd, const char *db, bool check_count,
bool do_send_error, char* crypted_scramble,int stage,
bool had_password)
{ {
thd->db=0; thd->db=0;
thd->db_length=0; thd->db_length=0;
USER_RESOURCES ur; USER_RESOURCES ur;
/* We shall avoid dupplicate user allocations here */
if (!(thd->user = my_strdup(user, MYF(0)))) if (!(thd->user))
{ if (!(thd->user = my_strdup(user, MYF(0))))
send_error(thd,ER_OUT_OF_RESOURCES); {
return 1; send_error(thd,ER_OUT_OF_RESOURCES);
} return 1;
}
thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user, thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
passwd, thd->scramble, &thd->priv_user, passwd, thd->scramble, &thd->priv_user,
protocol_version == 9 || protocol_version == 9 ||
!(thd->client_capabilities & !(thd->client_capabilities &
CLIENT_LONG_PASSWORD),&ur); CLIENT_LONG_PASSWORD),&ur,crypted_scramble,stage);
DBUG_PRINT("info", DBUG_PRINT("info",
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'", ("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_client_packet_length, thd->client_capabilities, thd->max_client_packet_length,
thd->host_or_ip, thd->priv_user, thd->host_or_ip, thd->priv_user,
passwd[0] ? "yes": "no", had_password ? "yes": "no",
thd->master_access, thd->db ? thd->db : "*none*")); thd->master_access, thd->db ? thd->db : "*none*"));
/* in case we're going to retry we should not send error message at this point */
if (thd->master_access & NO_ACCESS) if (thd->master_access & NO_ACCESS)
{ {
net_printf(thd, ER_ACCESS_DENIED_ERROR, if (do_send_error)
thd->user, {
net_printf(thd, ER_ACCESS_DENIED_ERROR,
thd->user,
thd->host_or_ip, thd->host_or_ip,
passwd[0] ? ER(ER_YES) : ER(ER_NO)); had_password ? ER(ER_YES) : ER(ER_NO));
mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR), mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
thd->user, thd->user,
thd->host_or_ip, thd->host_or_ip,
passwd[0] ? ER(ER_YES) : ER(ER_NO)); had_password ? ER(ER_YES) : ER(ER_NO));
return(1); // Error already given return(1); // Error already given
}
else
return(-1); // do not report error in special handshake
} }
if (check_count) if (check_count)
{ {
VOID(pthread_mutex_lock(&LOCK_thread_count)); VOID(pthread_mutex_lock(&LOCK_thread_count));
...@@ -505,9 +516,10 @@ check_connections(THD *thd) ...@@ -505,9 +516,10 @@ check_connections(THD *thd)
ulong pkt_len=0; ulong pkt_len=0;
{ {
/* buff[] needs to big enough to hold the server_version variable */ /* buff[] needs to big enough to hold the server_version variable */
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end; char buff[SERVER_VERSION_LENGTH +
SCRAMBLE_LENGTH+64],*end;
int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
CLIENT_PROTOCOL_41 | connection_auth_flag; CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION;
if (opt_using_transactions) if (opt_using_transactions)
client_flags|=CLIENT_TRANSACTIONS; client_flags|=CLIENT_TRANSACTIONS;
...@@ -529,6 +541,8 @@ check_connections(THD *thd) ...@@ -529,6 +541,8 @@ check_connections(THD *thd)
int2store(end+3,thd->server_status); int2store(end+3,thd->server_status);
bzero(end+5,13); bzero(end+5,13);
end+=18; end+=18;
// At this point we write connection message and read reply
if (net_write_command(net,(uchar) protocol_version, "", 0, buff, if (net_write_command(net,(uchar) protocol_version, "", 0, buff,
(uint) (end-buff)) || (uint) (end-buff)) ||
(pkt_len= my_net_read(net)) == packet_error || (pkt_len= my_net_read(net)) == packet_error ||
...@@ -581,19 +595,82 @@ check_connections(THD *thd) ...@@ -581,19 +595,82 @@ check_connections(THD *thd)
char *user= (char*) net->read_pos+5; char *user= (char*) net->read_pos+5;
char *passwd= strend(user)+1; char *passwd= strend(user)+1;
char *db=0; char *db=0;
if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH) if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
return ER_HANDSHAKE_ERROR; db=strend(passwd)+1;
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
db=strend(passwd)+1; /* We can get only old hash at this point */
if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
return ER_HANDSHAKE_ERROR;
if (thd->client_capabilities & CLIENT_INTERACTIVE) if (thd->client_capabilities & CLIENT_INTERACTIVE)
thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) && if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
opt_using_transactions) opt_using_transactions)
thd->net.return_status= &thd->server_status; thd->net.return_status= &thd->server_status;
net->read_timeout=(uint) thd->variables.net_read_timeout; net->read_timeout=(uint) thd->variables.net_read_timeout;
if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
return (-1); char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble and hash */
thd->password=test(passwd[0]);
/* Simple connect only for old clients. New clients always use secure auth */
bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
/* Store information if we used password. passwd will be dammaged */
bool using_password=test(passwd[0]);
/* Check user permissions. If password failure we'll get scramble back */
if (check_user(thd,COM_CONNECT, user, passwd, db, 1, simple_connect,
prepared_scramble,0,using_password))
{
/* If The client is old we just have to return error */
if (simple_connect)
return -1;
/* 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 (user)
{
strncpy(tmp_user,user,USERNAME_LENGTH+1);
/* Extra safety if we have too long data */
tmp_user[USERNAME_LENGTH]=0;
}
else
tmp_user[0]=0;
if (db)
{
strncpy(tmp_db,db,NAME_LEN+1);
tmp_db[NAME_LEN]=0;
}
else
tmp_db[0]=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, 1,prepared_scramble,1,using_password))
return -1;
}
thd->password=using_password;
return 0; return 0;
} }
...@@ -954,7 +1031,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -954,7 +1031,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
send_error(thd, ER_UNKNOWN_COM_ERROR); send_error(thd, ER_UNKNOWN_COM_ERROR);
break; break;
} }
if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0)) /* WARNING THIS HAS TO BE REWRITTEN */
char tmp_buffer[64];
printf("Change user called: %s %s %s\n",user,passwd,db);
if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0,1,tmp_buffer,0,1))
{ // Restore old user { // Restore old user
x_free(thd->user); x_free(thd->user);
x_free(thd->db); x_free(thd->db);
......
...@@ -3745,7 +3745,7 @@ text_or_password: ...@@ -3745,7 +3745,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,opt_old_passwords); make_scrambled_password(buff,$3.str,opt_old_passwords,&current_thd->rand);
$$=buff; $$=buff;
} }
} }
...@@ -4041,7 +4041,7 @@ grant_user: ...@@ -4041,7 +4041,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,opt_old_passwords); make_scrambled_password(buff,$4.str,opt_old_passwords,&current_thd->rand);
$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