Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
35ccfd0b
Commit
35ccfd0b
authored
Nov 24, 2002
by
peter@mysql.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
SCRUM: Main change for Secure connection handling. Still needs some more coding. Commit
done for merge with newer version of code.
parent
96131759
Changes
17
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
948 additions
and
244 deletions
+948
-244
client/mysqladmin.c
client/mysqladmin.c
+15
-7
include/mysql.h
include/mysql.h
+1
-1
include/mysql_com.h
include/mysql_com.h
+8
-1
libmysql/libmysql.c
libmysql/libmysql.c
+83
-9
mysql-test/install_test_db.sh
mysql-test/install_test_db.sh
+1
-1
mysql-test/t/rpl000017-slave.sh
mysql-test/t/rpl000017-slave.sh
+1
-1
scripts/mysql_fix_privilege_tables.sh
scripts/mysql_fix_privilege_tables.sh
+1
-0
scripts/mysql_install_db.sh
scripts/mysql_install_db.sh
+1
-1
sql/item_strfunc.cc
sql/item_strfunc.cc
+2
-2
sql/mini_client.cc
sql/mini_client.cc
+83
-7
sql/mysqld.cc
sql/mysqld.cc
+0
-1
sql/password.c
sql/password.c
+493
-46
sql/sql_acl.cc
sql/sql_acl.cc
+146
-134
sql/sql_acl.h
sql/sql_acl.h
+1
-1
sql/sql_class.h
sql/sql_class.h
+1
-1
sql/sql_parse.cc
sql/sql_parse.cc
+109
-29
sql/sql_yacc.yy
sql/sql_yacc.yy
+2
-2
No files found.
client/mysqladmin.c
View file @
35ccfd0b
...
...
@@ -87,7 +87,7 @@ enum commands {
ADMIN_FLUSH_HOSTS
,
ADMIN_FLUSH_TABLES
,
ADMIN_PASSWORD
,
ADMIN_PING
,
ADMIN_EXTENDED_STATUS
,
ADMIN_FLUSH_STATUS
,
ADMIN_FLUSH_PRIVILEGES
,
ADMIN_START_SLAVE
,
ADMIN_STOP_SLAVE
,
ADMIN_FLUSH_THREADS
ADMIN_FLUSH_THREADS
,
ADMIN_OLD_PASSWORD
};
static
const
char
*
command_names
[]
=
{
"create"
,
"drop"
,
"shutdown"
,
...
...
@@ -97,7 +97,7 @@ static const char *command_names[]= {
"flush-hosts"
,
"flush-tables"
,
"password"
,
"ping"
,
"extended-status"
,
"flush-status"
,
"flush-privileges"
,
"start-slave"
,
"stop-slave"
,
"flush-threads"
,
"flush-threads"
,
"old-password"
,
NullS
};
...
...
@@ -419,6 +419,7 @@ static my_bool sql_connect(MYSQL *mysql, uint wait)
static
int
execute_commands
(
MYSQL
*
mysql
,
int
argc
,
char
**
argv
)
{
const
char
*
status
;
struct
rand_struct
rand_st
;
for
(;
argc
>
0
;
argv
++
,
argc
--
)
{
...
...
@@ -721,9 +722,14 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
}
break
;
}
case
ADMIN_OLD_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
)
{
...
...
@@ -731,7 +737,8 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
return
1
;
}
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
crypted_pw
[
0
]
=
0
;
/* No password */
sprintf
(
buff
,
"set password='%s',sql_log_off=0"
,
crypted_pw
);
...
...
@@ -836,7 +843,8 @@ static void usage(void)
kill id,id,... Kill mysql threads"
);
#if MYSQL_VERSION_ID >= 32200
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
puts
(
"\
ping Check if mysqld is alive
\n
\
...
...
include/mysql.h
View file @
35ccfd0b
...
...
@@ -181,7 +181,7 @@ typedef struct st_mysql
enum
mysql_status
status
;
my_bool
free_me
;
/* If free in mysql_close */
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
...
...
include/mysql_com.h
View file @
35ccfd0b
...
...
@@ -280,10 +280,17 @@ extern unsigned long net_buffer_length;
void
randominit
(
struct
rand_struct
*
,
unsigned
long
seed1
,
unsigned
long
seed2
);
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
);
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
create_key_from_old_password
(
const
char
*
password
,
char
*
key
);
void
make_password_from_salt
(
char
*
to
,
unsigned
long
*
hash_res
,
uint8
password_version
);
char
*
scramble
(
char
*
to
,
const
char
*
message
,
const
char
*
password
,
my_bool
old_ver
);
...
...
libmysql/libmysql.c
View file @
35ccfd0b
...
...
@@ -67,7 +67,7 @@ ulong net_write_timeout= NET_WRITE_TIMEOUT;
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG \
| CLIENT_LOCAL_FILES | CLIENT_TRANSACTIONS \
| CLIENT_PROTOCOL_41)
| CLIENT_PROTOCOL_41
| CLIENT_SECURE_CONNECTION
)
#ifdef __WIN__
...
...
@@ -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
*
end
,
*
host_info
,
*
charset_name
;
char
password_hash
[
20
];
/* Used for tmp storage of stage1 hash */
my_socket
sock
;
uint32
ip_addr
;
struct
sockaddr_in
sock_addr
;
...
...
@@ -1789,7 +1790,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
if
((
pkt_length
=
net_safe_read
(
mysql
))
==
packet_error
)
goto
error
;
/* Check if version of protocol
l
matches current one */
/* Check if version of protocol matches current one */
mysql
->
protocol_version
=
net
->
read_pos
[
0
];
DBUG_DUMP
(
"packet"
,(
char
*
)
net
->
read_pos
,
10
);
...
...
@@ -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"
,
mysql
->
server_version
,
mysql
->
server_capabilities
,
mysql
->
server_status
,
client_flag
));
int3store
(
buff
+
2
,
max_allowed_packet
);
if
(
user
&&
user
[
0
])
strmake
(
buff
+
5
,
user
,
32
);
/* Max user name */
else
read_user_name
((
char
*
)
buff
+
5
);
/* We have to handle different version of handshake here */
#ifdef _CUSTOMCONFIG_
#include "_cust_libmysql.h";
#endif
DBUG_PRINT
(
"info"
,(
"user: %s"
,
buff
+
5
));
/*
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
))
{
end
=
strmake
(
end
+
1
,
db
,
NAME_LEN
);
mysql
->
db
=
my_strdup
(
db
,
MYF
(
MY_WME
));
db
=
0
;
}
/* Write authentication package */
if
(
my_net_write
(
net
,
buff
,(
ulong
)
(
end
-
buff
))
||
net_flush
(
net
))
{
net
->
last_errno
=
CR_SERVER_LOST
;
strmov
(
net
->
last_error
,
ER
(
net
->
last_errno
));
goto
error
;
}
/* We shall only query sever if it expect us to do so */
if
(
(
pkt_length
=
net_safe_read
(
mysql
))
==
packet_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 */
net
->
compress
=
1
;
if
(
db
&&
mysql_select_db
(
mysql
,
db
))
...
...
mysql-test/install_test_db.sh
View file @
35ccfd0b
...
...
@@ -123,7 +123,7 @@ then
c_u
=
"
$c_u
CREATE TABLE user ("
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
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
Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
c_u
=
"
$c_u
Update_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
...
...
mysql-test/t/rpl000017-slave.sh
View file @
35ccfd0b
...
...
@@ -5,7 +5,7 @@ master-bin.000001
4
127.0.0.1
replicate
aaaaaaaaaaaaaaab
thispartofthepasswordisnotused
aaaaaaaaaaaaaaab
$MASTER_MYPORT
1
0
...
...
scripts/mysql_fix_privilege_tables.sh
View file @
35ccfd0b
...
...
@@ -170,6 +170,7 @@ fi
@bindir@/mysql
-f
--user
=
root
--password
=
"
$root_password
"
--host
=
"
$host
"
mysql
<<
END_OF_DATA
alter table user
change password password char(45) not null,
add max_questions int(11) NOT NULL AFTER x509_subject,
add max_updates int(11) unsigned NOT NULL AFTER max_questions,
add max_connections int(11) unsigned NOT NULL AFTER max_updates;
...
...
scripts/mysql_install_db.sh
View file @
35ccfd0b
...
...
@@ -213,7 +213,7 @@ then
c_u
=
"
$c_u
CREATE TABLE user ("
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
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
Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
c_u
=
"
$c_u
Update_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
...
...
sql/item_strfunc.cc
View file @
35ccfd0b
...
...
@@ -1279,7 +1279,7 @@ String *Item_func_password::val_str(String *str)
return
0
;
if
(
res
->
length
()
==
0
)
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
());
return
str
;
}
...
...
@@ -1291,7 +1291,7 @@ String *Item_func_old_password::val_str(String *str)
return
0
;
if
(
res
->
length
()
==
0
)
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
());
return
str
;
}
...
...
sql/mini_client.cc
View file @
35ccfd0b
...
...
@@ -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__)
#define perror(A)
...
...
@@ -488,6 +490,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
uint
net_read_timeout
)
{
char
buff
[
NAME_LEN
+
USERNAME_LENGTH
+
100
],
*
end
,
*
host_info
;
char
password_hash
[
20
];
my_socket
sock
;
ulong
ip_addr
;
struct
sockaddr_in
sock_addr
;
...
...
@@ -510,7 +513,6 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
user
?
user
:
"(Null)"
,
net_read_timeout
,
(
uint
)
slave_net_timeout
));
net
->
vio
=
0
;
/* If something goes wrong */
mysql
->
charset
=
default_charset_info
;
/* Set character set */
if
(
!
port
)
...
...
@@ -799,22 +801,96 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
}
DBUG_PRINT
(
"info"
,(
"user: %s"
,
buff
+
5
));
/*
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
));
if
(
db
)
/* Add database if needed */
if
(
db
&&
(
mysql
->
server_capabilities
&
CLIENT_CONNECT_WITH_DB
))
{
end
=
strmake
(
end
+
1
,
db
,
NAME_LEN
);
mysql
->
db
=
my_strdup
(
db
,
MYF
(
MY_WME
));
db
=
0
;
}
/* Write authentication package */
if
(
my_net_write
(
net
,
buff
,(
ulong
)
(
end
-
buff
))
||
net_flush
(
net
))
{
net
->
last_errno
=
CR_SERVER_LOST
;
strmov
(
net
->
last_error
,
ER
(
net
->
last_errno
));
goto
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
;
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 */
net
->
compress
=
1
;
DBUG_PRINT
(
"exit"
,(
"Mysql handler: %lx"
,
mysql
));
...
...
sql/mysqld.cc
View file @
35ccfd0b
...
...
@@ -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
|
OPTION_BIN_LOG
|
OPTION_QUOTE_SHOW_CREATE
);
uint
protocol_version
=
PROTOCOL_VERSION
;
uint
connection_auth_flag
=
0
;
/* Supported authentication mode */
struct
system_variables
global_system_variables
;
struct
system_variables
max_system_variables
;
ulong
keybuff_size
,
table_cache_size
,
...
...
sql/password.c
View file @
35ccfd0b
...
...
@@ -32,6 +32,24 @@
Example:
update user set password=PASSWORD("hello") where user="test"
This saves a hashed number as a string in the password field.
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.
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.
*****************************************************************************/
#include <my_global.h>
...
...
@@ -45,9 +63,22 @@
/* Character to use as version identifier for version 4.1 */
#define PVERSION41_CHAR '*'
/* Scramble length for new password version */
#define SCRAMBLE41_LENGTH 20
/*
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.# */
...
...
@@ -60,6 +91,19 @@ void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
rand_st
->
seed2
=
seed2
%
rand_st
->
max_value
;
}
/*
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
;
...
...
@@ -68,6 +112,18 @@ static void old_randominit(struct rand_struct *rand_st,ulong seed1)
rand_st
->
seed1
=
seed1
;
rand_st
->
seed2
=
seed1
/
2
;
}
/*
Generate Random number
SYNOPSIS
rnd()
rand_st INOUT Structure used for number generation
RETURN
Generated pseudo random number
*/
double
rnd
(
struct
rand_struct
*
rand_st
)
{
rand_st
->
seed1
=
(
rand_st
->
seed1
*
3
+
rand_st
->
seed2
)
%
rand_st
->
max_value
;
...
...
@@ -75,6 +131,75 @@ double rnd(struct rand_struct *rand_st)
return
(((
double
)
rand_st
->
seed1
)
/
rand_st
->
max_value_dbl
);
}
/*
Generate String of printable random characters of requested length
String will not be zero terminated.
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. */
while
(
target
<
end
)
{
*
target
=
rnd
(
rand_st
)
*
94
+
33
;
target
++
;
}
}
/*
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
*/
inline
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
;
from
++
;
to
++
;
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
*/
void
hash_password
(
ulong
*
result
,
const
char
*
password
)
{
register
ulong
nr
=
1345345333L
,
add
=
7
,
nr2
=
0x12345671L
;
...
...
@@ -94,15 +219,75 @@ void hash_password(ulong *result, const char *password)
}
/*
Stage one password hashing.
Used in MySQL 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
*/
void
make_scrambled_password
(
char
*
to
,
const
char
*
password
,
my_bool
force_old_scramble
)
inline
void
password_hash_stage1
(
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
,(
int8
*
)
&
password
[
0
],
1
);
}
sha1_result
(
&
context
,(
uint8
*
)
to
);
}
/*
Stage two password hashing.
Used in MySQL 4.1 password handling
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
RETURN
none
*/
inline
void
password_hash_stage2
(
char
*
to
,
const
char
*
salt
)
{
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
;
sha1_reset
(
&
context
);
sha1_input
(
&
context
,(
uint8
*
)
salt
,
4
);
sha1_input
(
&
context
,
to
,
SHA1_HASH_SIZE
);
sha1_result
(
&
context
,(
uint8
*
)
to
);
}
/*
Create password to be stored in user database from raw string
Handles both MySQL 4.1 and Pre-MySQL 4.1 passwords
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
*/
void
make_scrambled_password
(
char
*
to
,
const
char
*
password
,
my_bool
force_old_scramble
,
struct
rand_struct
*
rand_st
)
{
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 */
{
...
...
@@ -112,27 +297,16 @@ void make_scrambled_password(char *to,const char *password,my_bool force_old_scr
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
;
/* Random returns number from 0 to 1 so this would be good salt generation.
*/
salt
=
rnd
(
rand_st
)
*
65535
+
1
;
/* 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
);
sprintf
(
to
+
1
,
"%04x"
,
salt
);
/* First hasing is done without salt */
password_hash_stage1
(
digest
,
password
);
/* Second stage is done with salt */
password_hash_stage2
(
digest
,(
char
*
)
to
+
1
),
/* Print resulting hash into the password*/
sprintf
(
&
(
to
[
5
])
,
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
],
...
...
@@ -140,14 +314,111 @@ void make_scrambled_password(char *to,const char *password,my_bool force_old_scr
}
}
uint
get_password_length
(
my_bool
force_old_scramble
)
/*
Convert password from binary string form to salt form
Used for MySQL 4.1 password handling
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
*/
void
get_salt_from_bin_password
(
ulong
*
res
,
unsigned
char
*
password
,
ulong
salt
)
{
unsigned
char
*
password_end
=
password
+
SCRAMBLE41_LENGTH
;
*
res
=
salt
;
res
++
;
bzero
(
res
,
5
*
sizeof
(
res
[
0
]));
/* Process password of known length*/
while
(
password
<
password_end
)
{
ulong
val
=
0
;
uint
i
;
for
(
i
=
0
;
i
<
4
;
i
++
)
val
=
(
val
<<
8
)
+
(
*
password
++
);
*
res
++=
val
;
}
}
/*
Validate password for MySQL 4.1 password handling.
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
*/
my_bool
validate_password
(
const
char
*
password
,
const
char
*
message
,
ulong
*
salt
)
{
char
buffer
[
SCRAMBLE41_LENGTH
];
/* Used for password validation */
char
tmpsalt
[
8
];
/* Temporary value to convert salt to string form */
int
i
;
ulong
salt_candidate
[
6
];
/* Computed candidate salt */
/* 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
,
buffer
,
salt
[
0
]);
/* Now we shall get exactly the same password as we have stored for user */
for
(
i
=
1
;
i
<
6
;
i
++
)
if
(
salt
[
i
]
!=
salt_candidate
[
i
])
return
1
;
/* Or password correct*/
return
0
;
}
/*
Get length of password string which is stored in mysql.user table
SYNOPSIS
get_password_length()
force_old_scramble IN If we wish to use pre 4.1 scramble format
RETURN
password length >0
*/
inline
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
)
/*
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
*/
inline
uint8
get_password_version
(
const
char
*
password
)
{
if
(
password
==
NULL
)
return
0
;
if
(
password
[
0
]
==
PVERSION41_CHAR
)
return
PVERSION41_CHAR
;
...
...
@@ -155,6 +426,19 @@ uint8 get_password_version(const char* password)
}
/*
Get integer value of Hex character
SYNOPSIS
char_val()
X IN Character to find value for
RETURN
Appropriate integer value
*/
inline
uint
char_val
(
char
X
)
{
return
(
uint
)
(
X
>=
'0'
&&
X
<=
'9'
?
X
-
'0'
:
...
...
@@ -162,30 +446,45 @@ inline uint char_val(char X)
X
-
'a'
+
10
);
}
/*
** This code detects new version password by leading char.
** Old password has to be divisible by 8 length
** do not forget to increase array length if you need longer passwords
** THIS FUNCTION DOES NOT HAVE ANY LENGTH CHECK
Get Binary salt from password as in mysql.user format
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
)
{
bzero
(
res
,
6
*
sizeof
(
res
[
0
]));
if
(
password
)
/
/ zero salt corresponds to empty password
if
(
password
)
/
* zero salt corresponds to empty password */
{
if
(
password
[
0
]
==
PVERSION41_CHAR
)
/
/ if new password
if
(
password
[
0
]
==
PVERSION41_CHAR
)
/
* if new password */
{
uint
val
=
0
;
uint
i
;
password
++
;
/
/ skip version identifier.
password
++
;
/
* skip version identifier */
/
/get hashing salt from password and store in in the start of array
/
*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
/* 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
;
...
...
@@ -198,40 +497,168 @@ void get_salt_from_password(ulong *res,const char *password)
return
;
}
/*
Get string version as stored in mysql.user from salt form
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
*/
void
make_password_from_salt
(
char
*
to
,
ulong
*
hash_res
,
uint8
password_version
)
{
if
(
!
password_version
)
/
/ Handling of old passwords.
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"
,
(
uin
t
)
hash_res
[
0
],
hash_res
[
1
],
sprintf
(
to
,
"%c%04x%08lx%08lx%08lx%08lx%08lx"
,
PVERSION41_CHAR
,(
unsigned
shor
t
)
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
else
/
* Just use empty password if we can't handle it. This should not happen */
to
[
0
]
=
'\0'
;
}
/*
* Genererate a new message based on message and password
* The same thing is done in client and server and the results are checked.
*/
Convert password in salted form to binary string password and hash-salt
For old password this involes one more hashing
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
*/
void
get_hash_and_password
(
ulong
*
salt
,
uint8
pversion
,
char
*
hash
,
unsigned
char
*
bin_password
)
{
int
t
;
ulong
*
salt_end
;
ulong
val
;
SHA1_CONTEXT
context
;
unsigned
char
*
bp
;
/* Binary password loop pointer */
if
(
pversion
)
/* New password version assumed */
{
salt_end
=
salt
+
6
;
sprintf
(
hash
,
"%04x"
,(
unsigned
short
)
salt
[
0
]);
salt
++
;
/* position to the second element */
while
(
salt
<
salt_end
)
/* Iterate over these elements*/
{
val
=*
salt
;
for
(
t
=
3
;
t
>=
0
;
t
--
)
{
bin_password
[
t
]
=
val
%
256
;
val
>>=
8
;
/* Scroll 8 bits to get next part*/
}
bin_password
+=
4
;
/* Get to next 4 chars*/
salt
++
;
}
}
else
{
/* Use zero starting hash as an indication of old password */
hash
[
0
]
=
0
;
salt_end
=
salt
+
2
;
bp
=
bin_password
;
/* 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
]
=
val
%
256
;
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
);
}
}
/*
Create key from old password to decode scramble
Used in 4.1 authentication with passwords stored old way
SYNOPSIS
create_key_from_old_password()
passwd IN Password used for key generation
key OUT Created 20 bytes key
RETURN
None
*/
void
create_key_from_old_password
(
const
char
*
passwd
,
char
*
key
)
{
char
buffer
[
20
];
/* 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
);
}
/*
Scramble string with password
Used at pre 4.1 authentication phase.
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
*/
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
];
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
);
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
(
*
m
essage
++
)
while
(
*
m
sg
++
)
*
to
++=
(
char
)
(
floor
(
rnd
(
&
rand_st
)
*
31
)
+
64
);
if
(
!
old_ver
)
{
/* Make it harder to break */
...
...
@@ -245,6 +672,22 @@ char *scramble(char *to,const char *message,const char *password,
}
/*
Check scrambled message
Used for pre 4.1 password handling
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
RETURN
0 Password correct
!0 Password invalid
*/
my_bool
check_scramble
(
const
char
*
scrambled
,
const
char
*
message
,
ulong
*
hash_pass
,
my_bool
old_ver
)
{
...
...
@@ -252,8 +695,12 @@ my_bool check_scramble(const char *scrambled, const char *message,
ulong
hash_message
[
2
];
char
buff
[
16
],
*
to
,
extra
;
/* Big enough for check */
const
char
*
pos
;
char
message_buffer
[
9
];
/* Copy of message */
memcpy
(
message_buffer
,
message
,
8
);
/* Old auth uses 8 bytes at maximum */
message_buffer
[
8
]
=
0
;
hash_password
(
hash_message
,
message
);
hash_password
(
hash_message
,
message
_buffer
);
if
(
old_ver
)
old_randominit
(
&
rand_st
,
hash_pass
[
0
]
^
hash_message
[
0
]);
else
...
...
sql/sql_acl.cc
View file @
35ccfd0b
...
...
@@ -32,7 +32,6 @@
#include <assert.h>
#include <stdarg.h>
extern
uint
connection_auth_flag
;
// any better way to do it ?
struct
acl_host_and_ip
{
...
...
@@ -146,8 +145,6 @@ my_bool acl_init(bool dont_read_acl_tables)
(
void
(
*
)(
void
*
))
free
);
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 */
}
...
...
@@ -224,7 +221,6 @@ my_bool acl_init(bool dont_read_acl_tables)
DBUG_PRINT
(
"info"
,(
"user table fields: %d"
,
table
->
fields
));
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
)))
{
ACL_USER
user
;
...
...
@@ -239,7 +235,11 @@ 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)"
,
user
.
user
?
user
.
user
:
""
);
/* purecov: tested */
}
else
if
(
length
%
8
&&
length
!=
45
)
// This holds true for passwords
else
/* non emptpy 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"
,
...
...
@@ -247,20 +247,8 @@ my_bool acl_init(bool dont_read_acl_tables)
user
.
host
.
hostname
?
user
.
host
.
hostname
:
""
);
/* purecov: tested */
continue
;
/* purecov: tested */
}
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
;
}
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
?
...
...
@@ -319,17 +307,6 @@ my_bool acl_init(bool dont_read_acl_tables)
end_read_record
(
&
read_record_info
);
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
);
/* DEBUG to be removed */
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
));
while
(
!
(
read_record_info
.
read_record
(
&
read_record_info
)))
...
...
@@ -509,6 +486,26 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
return
0
;
}
/*
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
[
20
];
/* Generate new long scramble for the thread */
create_random_string
(
20
,
&
thd
->
rand
,
thd
->
scramble
);
thd
->
scramble
[
20
]
=
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
);
/* Finally encrypt password to get prepared scramble */
password_crypt
(
thd
->
scramble
,
prepared_scramble
+
4
,
bin_password
,
20
);
}
/*
Get master privilges for user (priviliges for all tables).
...
...
@@ -517,10 +514,11 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
ulong
acl_getroot
(
THD
*
thd
,
const
char
*
host
,
const
char
*
ip
,
const
char
*
user
,
const
char
*
password
,
const
char
*
message
,
char
**
priv_user
,
bool
old_ver
,
USER_RESOURCES
*
mqh
)
bool
old_ver
,
USER_RESOURCES
*
mqh
,
char
*
prepared_scramble
,
int
stage
)
{
ulong
user_access
=
NO_ACCESS
;
*
priv_user
=
(
char
*
)
user
;
bool
password_correct
=
0
;
DBUG_ENTER
(
"acl_getroot"
);
bzero
(
mqh
,
sizeof
(
USER_RESOURCES
));
...
...
@@ -543,9 +541,39 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
if
(
compare_hostname
(
&
acl_user
->
host
,
host
,
ip
))
{
if
(
!
acl_user
->
password
&&
!*
password
||
(
acl_user
->
password
&&
*
password
&&
!
check_scramble
(
password
,
message
,
acl_user
->
salt
,
(
my_bool
)
old_ver
)))
(
acl_user
->
password
&&
*
password
))
{
/* Quick check and accept for empty passwords*/
if
(
!
acl_user
->
password
&&
!*
password
)
password_correct
=
1
;
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
/* Password incorrect */
/* At the first stage - prepare scramble */
if
(
!
stage
)
prepare_scramble
(
thd
,
acl_user
,
prepared_scramble
);
}
}
/* If password correct continue with checking other limitations */
if
(
password_correct
)
{
#ifdef HAVE_OPENSSL
Vio
*
vio
=
thd
->
net
.
vio
;
...
...
@@ -634,7 +662,9 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
if
(
!
acl_user
->
user
)
*
priv_user
=
(
char
*
)
""
;
// Change to anonymous user /* purecov: inspected */
break
;
}
}
// correct password
}
// found matching user
#ifndef ALLOW_DOWNGRADE_OF_USERS
break
;
// Wrong password breaks loop /* purecov: inspected */
#endif
...
...
@@ -704,12 +734,6 @@ static void acl_update_user(const char *user, const char *host,
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
);
// 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
;
...
...
@@ -746,10 +770,6 @@ static void acl_insert_user(const char *user, const char *host,
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
);
if
(
acl_user
.
pversion
)
connection_auth_flag
|=
CLIENT_SECURE_CONNECTION
;
else
connection_auth_flag
|=
CLIENT_LONG_PASSWORD
;
}
VOID
(
push_dynamic
(
&
acl_users
,(
gptr
)
&
acl_user
));
...
...
@@ -1124,14 +1144,7 @@ bool change_password(THD *thd, const char *host, const char *user,
if
(
!
new_password
[
0
])
acl_user
->
password
=
0
;
else
{
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
VOID
(
pthread_mutex_unlock
(
&
acl_cache
->
lock
));
...
...
@@ -2241,7 +2254,6 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
bool
create_new_users
=
0
;
TABLE_LIST
tables
[
2
];
DBUG_ENTER
(
"mysql_grant"
);
if
(
!
initialized
)
{
send_error
(
thd
,
ER_UNKNOWN_COM_ERROR
);
/* purecov: tested */
...
...
sql/sql_acl.h
View file @
35ccfd0b
...
...
@@ -88,7 +88,7 @@ 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
,
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
check_change_password
(
THD
*
thd
,
const
char
*
host
,
const
char
*
user
);
bool
change_password
(
THD
*
thd
,
const
char
*
host
,
const
char
*
user
,
...
...
sql/sql_class.h
View file @
35ccfd0b
...
...
@@ -496,7 +496,7 @@ class THD :public ilink {
uint
select_number
;
//number of select (used for EXPLAIN)
/* variables.transaction_isolation is reset to this after each commit */
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
bool
slave_thread
;
bool
set_query_id
,
locked
,
count_cuted_fields
,
some_tables_deleted
;
...
...
sql/sql_parse.cc
View file @
35ccfd0b
...
...
@@ -45,13 +45,13 @@
#define MIN_HANDSHAKE_SIZE 6
#endif
/* HAVE_OPENSSL */
#define SCRAMBLE_LENGTH 8
#define SCRAMBLE41_LENGTH 20
#define MEM_ROOT_BLOCK_SIZE 8192
#define MEM_ROOT_PREALLOC 8192
#define TRANS_MEM_ROOT_BLOCK_SIZE 4096
#define TRANS_MEM_ROOT_PREALLOC 4096
extern
uint
connection_auth_flag
;
extern
int
yyparse
(
void
);
extern
"C"
pthread_mutex_t
THR_LOCK_keycache
;
...
...
@@ -180,12 +180,15 @@ 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
,
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_length
=
0
;
USER_RESOURCES
ur
;
/* We shall avoid dupplicate user allocations here */
if
(
!
(
thd
->
user
))
if
(
!
(
thd
->
user
=
my_strdup
(
user
,
MYF
(
0
))))
{
send_error
(
thd
,
ER_OUT_OF_RESOURCES
);
...
...
@@ -195,25 +198,33 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
passwd
,
thd
->
scramble
,
&
thd
->
priv_user
,
protocol_version
==
9
||
!
(
thd
->
client_capabilities
&
CLIENT_LONG_PASSWORD
),
&
ur
);
CLIENT_LONG_PASSWORD
),
&
ur
,
crypted_scramble
,
stage
);
DBUG_PRINT
(
"info"
,
(
"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
->
host_or_ip
,
thd
->
priv_user
,
passwd
[
0
]
?
"yes"
:
"no"
,
had_password
?
"yes"
:
"no"
,
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
(
do_send_error
)
{
net_printf
(
thd
,
ER_ACCESS_DENIED_ERROR
,
thd
->
user
,
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
),
thd
->
user
,
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
}
else
return
(
-
1
);
// do not report error in special handshake
}
if
(
check_count
)
{
VOID
(
pthread_mutex_lock
(
&
LOCK_thread_count
));
...
...
@@ -505,9 +516,10 @@ check_connections(THD *thd)
ulong
pkt_len
=
0
;
{
/* 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
|
CLIENT_PROTOCOL_41
|
connection_auth_flag
;
CLIENT_PROTOCOL_41
|
CLIENT_SECURE_CONNECTION
;
if
(
opt_using_transactions
)
client_flags
|=
CLIENT_TRANSACTIONS
;
...
...
@@ -529,6 +541,8 @@ check_connections(THD *thd)
int2store
(
end
+
3
,
thd
->
server_status
);
bzero
(
end
+
5
,
13
);
end
+=
18
;
// 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
||
...
...
@@ -581,19 +595,82 @@ check_connections(THD *thd)
char
*
user
=
(
char
*
)
net
->
read_pos
+
5
;
char
*
passwd
=
strend
(
user
)
+
1
;
char
*
db
=
0
;
if
(
passwd
[
0
]
&&
strlen
(
passwd
)
!=
SCRAMBLE_LENGTH
)
return
ER_HANDSHAKE_ERROR
;
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
)
thd
->
variables
.
net_wait_timeout
=
thd
->
variables
.
net_interactive_timeout
;
if
((
thd
->
client_capabilities
&
CLIENT_TRANSACTIONS
)
&&
opt_using_transactions
)
thd
->
net
.
return_status
=
&
thd
->
server_status
;
net
->
read_timeout
=
(
uint
)
thd
->
variables
.
net_read_timeout
;
if
(
check_user
(
thd
,
COM_CONNECT
,
user
,
passwd
,
db
,
1
))
return
(
-
1
);
thd
->
password
=
test
(
passwd
[
0
]);
char
prepared_scramble
[
SCRAMBLE41_LENGTH
+
4
];
/* Buffer for scramble and hash */
/* 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
;
}
...
...
@@ -954,7 +1031,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
send_error
(
thd
,
ER_UNKNOWN_COM_ERROR
);
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
x_free
(
thd
->
user
);
x_free
(
thd
->
db
);
...
...
sql/sql_yacc.yy
View file @
35ccfd0b
...
...
@@ -3745,7 +3745,7 @@ text_or_password:
else
{
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
,¤t_thd->rand
);
$$=buff;
}
}
...
...
@@ -4041,7 +4041,7 @@ grant_user:
char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1);
if (buff)
{
make_scrambled_password(buff,$4.str,opt_old_passwords);
make_scrambled_password(buff,$4.str,opt_old_passwords
,¤t_thd->rand
);
$1->password.str=buff;
$1->password.length=HASH_PASSWORD_LENGTH;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment