#At file:///home/thek/bzr/mysql-trunk-security/ based on revid:tor.didriksen@strippedah1q7
3311 Kristofer Pettersson 2011-05-27
WL5602 Preview patch
This patch introduces a new built in authentication plugin
for salted SHA-2 hashed passwords.
The ability to change default authentication plugin for
CREATE USER, GRANT USER and PASSWORD statements is also
introduced.
added:
include/crypt_genhash_impl.h
mysql-test/r/plugin_auth_sha256.result
mysql-test/t/plugin_auth_sha256.test
sql-common/crypt_genhash_impl.cc
modified:
include/password.h
libmysql/CMakeLists.txt
mysql-test/r/grant.result
mysql-test/r/plugin_auth.result
mysql-test/r/plugin_auth_qa.result
mysql-test/r/plugin_auth_qa_1.result
mysql-test/r/plugin_auth_qa_2.result
mysql-test/t/plugin_auth.test
mysql-test/t/plugin_auth_qa.test
scripts/mysql_system_tables.sql
scripts/mysql_system_tables_data.sql
sql-common/client.c
sql/CMakeLists.txt
sql/item_strfunc.cc
sql/item_strfunc.h
sql/password.c
sql/set_var.cc
sql/sql_acl.cc
sql/sql_acl.h
sql/sql_class.h
sql/sql_parse.cc
sql/sql_yacc.yy
sql/structs.h
sql/sys_vars.cc
=== added file 'include/crypt_genhash_impl.h'
--- a/include/crypt_genhash_impl.h 1970-01-01 00:00:00 +0000
+++ b/include/crypt_genhash_impl.h 2011-05-27 14:40:44 +0000
@@ -0,0 +1,32 @@
+#ifndef CRYPT_HASHGEN_IMPL_H
+#define CRYPT_HASHGEN_IMPL_H
+#define ROUNDS_DEFAULT 5000
+#define ROUNDS_MIN 1000
+#define ROUNDS_MAX 999999999
+#define MIXCHARS 32
+#define CRYPT_SALT_LENGTH 20
+#define CRYPT_MAGIC_LENGTH 3
+#define CRYPT_PARAM_LENGTH 13
+#define CRYPT_MAX_PASSWORD_SIZE (CRYPT_SALT_LENGTH + \
+ 43 + \
+ CRYPT_MAGIC_LENGTH + \
+ CRYPT_PARAM_LENGTH)
+
+int extract_user_salt(char **salt_begin,
+ char **salt_end);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+char *
+crypt_genhash_impl(char *ctbuffer,
+ size_t ctbufflen,
+ const char *plaintext,
+ int plaintext_len,
+ const char *switchsalt,
+ const char **params);
+void generate_user_salt(char *buffer, int buffer_len);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif
=== modified file 'include/password.h'
--- a/include/password.h 2010-03-31 14:05:33 +0000
+++ b/include/password.h 2011-05-27 14:40:44 +0000
@@ -18,12 +18,18 @@
#include "my_global.h"
+struct rand_struct *get_sql_rand();
+
C_MODE_START
void my_make_scrambled_password_323(char *to, const char *password,
size_t pass_len);
void my_make_scrambled_password(char *to, const char *password,
size_t pass_len);
+void my_make_scrambled_password_sha1(char *to, const char *password,
+ size_t pass_len);
+void my_make_scrambled_password_323(char *to, const char *password,
+ size_t pass_len);
void hash_password(ulong *result, const char *password, uint password_len);
=== modified file 'libmysql/CMakeLists.txt'
--- a/libmysql/CMakeLists.txt 2011-03-28 08:49:43 +0000
+++ b/libmysql/CMakeLists.txt 2011-05-27 14:40:44 +0000
@@ -141,6 +141,7 @@ SET(CLIENT_SOURCES
../sql-common/client.c
../sql-common/my_time.c
../sql-common/client_plugin.c
+ ../sql-common/crypt_genhash_impl.cc
../sql/net_serv.cc
../sql-common/pack.c
../sql/password.c
=== modified file 'mysql-test/r/grant.result'
Binärfilerna a/mysql-test/r/grant.result 2011-03-21 14:50:06 +0000 och b/mysql-test/r/grant.result 2011-05-27 14:40:44 +0000 skiljer
=== modified file 'mysql-test/r/plugin_auth.result'
--- a/mysql-test/r/plugin_auth.result 2011-04-07 09:55:09 +0000
+++ b/mysql-test/r/plugin_auth.result 2011-05-27 14:40:44 +0000
@@ -36,6 +36,7 @@ select USER(),CURRENT_USER();
USER() CURRENT_USER()
plug@localhost plug_dest@%
## test SET PASSWORD
+Setting password is allowed but it won't affect the authentication mechanism.
SET PASSWORD = PASSWORD('plug_dest');
Warnings:
Note 1699 SET PASSWORD has no significance for users authenticating via plugins
@@ -45,7 +46,7 @@ ERROR 28000: Access denied for user 'plu
## test correct default plugin
select USER(),CURRENT_USER();
USER() CURRENT_USER()
-plug@localhost plug@%
+plug@localhost plug_dest@%
## test no_auto_create_user sql mode with plugin users
SET @@sql_mode=no_auto_create_user;
GRANT INSERT ON TEST.* TO grant_user IDENTIFIED WITH 'test_plugin_server';
@@ -85,9 +86,9 @@ CREATE TABLE t1 (a INT);
DROP TABLE t1;
DROP USER new_grant_user;
# try re-create existing user via GRANT IDENTIFIED WITH
+GRANTS which don't affect current plugin are allowed!
GRANT ALL PRIVILEGES ON test_grant_db.* TO plug
IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
-ERROR HY000: GRANT with IDENTIFIED WITH is illegal because the user plug already exists
GRANT ALL PRIVILEGES ON test_grant_db.* TO plug_dest
IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
ERROR HY000: GRANT with IDENTIFIED WITH is illegal because the user plug_dest already exists
=== modified file 'mysql-test/r/plugin_auth_qa.result'
--- a/mysql-test/r/plugin_auth_qa.result 2011-03-18 14:16:17 +0000
+++ b/mysql-test/r/plugin_auth_qa.result 2011-05-27 14:40:44 +0000
@@ -105,7 +105,7 @@ CREATE USER plug_dest IDENTIFIED BY 'plu
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
plug test_plugin_server plug_dest
-plug_dest NULL
+plug_dest mysql_native_password
DROP USER plug, plug_dest;
CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
@@ -115,7 +115,7 @@ DROP USER plug;
CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-plug_dest NULL
+plug_dest mysql_native_password
DROP USER plug_dest;
GRANT ALL PRIVILEGES ON test_user_db.* TO plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
@@ -125,7 +125,7 @@ CREATE USER plug_dest IDENTIFIED BY 'plu
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
plug test_plugin_server plug_dest
-plug_dest NULL
+plug_dest mysql_native_password
DROP USER plug, plug_dest;
GRANT ALL PRIVILEGES ON test_user_db.* TO plug IDENTIFIED WITH test_plugin_server AS 'plug_dest';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
@@ -135,7 +135,7 @@ DROP USER plug;
CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-plug_dest NULL
+plug_dest mysql_native_password
DROP USER plug_dest;
CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
@@ -145,7 +145,7 @@ GRANT ALL PRIVILEGES ON test_user_db.* T
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
plug test_plugin_server plug_dest
-plug_dest NULL
+plug_dest mysql_native_password
DROP USER plug, plug_dest;
CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
@@ -155,13 +155,13 @@ DROP USER plug;
GRANT ALL PRIVILEGES ON test_user_db.* TO plug_dest IDENTIFIED BY 'plug_dest_passwd';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-plug_dest NULL
+plug_dest mysql_native_password
DROP USER plug_dest;
CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
+GRANTs which doesn't change the plugin are allowed
GRANT ALL PRIVILEGES ON test_user_db.* TO plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
-ERROR HY000: GRANT with IDENTIFIED WITH is illegal because the user plug already exists
+GRANTs which doesn't change the plugin are allowed
GRANT ALL PRIVILEGES ON test_user_db.* TO plug IDENTIFIED WITH 'test_plugin_server';
-ERROR HY000: GRANT with IDENTIFIED WITH is illegal because the user plug already exists
DROP USER plug;
GRANT ALL PRIVILEGES ON test_user_db.* TO plug IDENTIFIED WITH test_plugin_server AS 'plug_dest';
CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
@@ -176,7 +176,7 @@ plug test_plugin_server plug_dest
GRANT ALL PRIVILEGES ON test_user_db.* TO plug IDENTIFIED BY 'plug_dest_passwd';
SELECT user,plugin,authentication_string,password FROM mysql.user WHERE user != 'root';
user plugin authentication_string password
-plug test_plugin_server plug_dest *939AEE68989794C0F408277411C26055CDF41119
+plug test_plugin_server plug_dest
DROP USER plug;
GRANT ALL PRIVILEGES ON test_user_db.* TO plug IDENTIFIED WITH test_plugin_server AS 'plug_dest';
CREATE USER plug IDENTIFIED BY 'plug_dest_passwd';
@@ -210,7 +210,7 @@ DROP USER plüg;
CREATE USER plüg_dest IDENTIFIED BY 'plug_dest_passwd';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-plüg_dest NULL
+plüg_dest mysql_native_password
DROP USER plüg_dest;
SET NAMES ascii;
CREATE USER 'plüg' IDENTIFIED WITH 'test_plugin_server' AS 'plüg_dest';
@@ -221,7 +221,7 @@ DROP USER 'plüg';
CREATE USER 'plüg_dest' IDENTIFIED BY 'plug_dest_passwd';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-pl??g_dest NULL
+pl??g_dest mysql_native_password
DROP USER 'plüg_dest';
SET NAMES latin1;
========== test 1.1.1.5 ====================================
@@ -235,7 +235,7 @@ DROP USER 'plug';
CREATE USER 'plüg_dest' IDENTIFIED BY 'plug_dest_passwd';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-plüg_dest NULL
+plüg_dest mysql_native_password
DROP USER 'plüg_dest';
SET NAMES utf8;
CREATE USER plüg IDENTIFIED WITH 'test_plügin_server' AS 'plüg_dest';
@@ -248,7 +248,7 @@ DROP USER 'plüg';
CREATE USER 'plüg_dest' IDENTIFIED BY 'plug_dest_passwd';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-plüg_dest NULL
+plüg_dest mysql_native_password
DROP USER 'plüg_dest';
CREATE USER plüg IDENTIFIED WITH test_plugin_server AS 'plüg_dest';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
@@ -258,7 +258,7 @@ DROP USER plüg;
CREATE USER plüg_dest IDENTIFIED BY 'plug_dest_passwd';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-plüg_dest NULL
+plüg_dest mysql_native_password
DROP USER plüg_dest;
========== test 1.1.1.2/1.1.2.2=============================
SET @auth_name= 'test_plugin_server';
@@ -278,7 +278,7 @@ DROP USER plug;
CREATE USER 'hh''s_plug_dest' IDENTIFIED BY 'plug_dest_passwd';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-hh's_plug_dest NULL
+hh's_plug_dest mysql_native_password
DROP USER 'hh''s_plug_dest';
========== test 1.1.1.4 ====================================
CREATE USER plug IDENTIFIED WITH hh''s_test_plugin_server AS 'plug_dest';
@@ -294,7 +294,7 @@ GRANT ALL PRIVILEGES ON test_user_db.* T
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
grant_user test_plugin_server plug_dest
-plug_dest NULL
+plug_dest mysql_native_password
DROP USER grant_user,plug_dest;
set @save_sql_mode= @@sql_mode;
SET @@sql_mode=no_auto_create_user;
@@ -315,13 +315,13 @@ CREATE USER plug_dest IDENTIFIED BY 'plu
SELECT user,plugin,authentication_string,password FROM mysql.user WHERE user != 'root';
user plugin authentication_string password
grant_user test_plugin_server plug_dest
-plug_dest NULL *939AEE68989794C0F408277411C26055CDF41119
+plug_dest mysql_native_password *939AEE68989794C0F408277411C26055CDF41119
DROP USER plug_dest;
GRANT ALL PRIVILEGES ON test_user_db.* TO plug_dest IDENTIFIED BY 'plug_user_passwd';
SELECT user,plugin,authentication_string,password FROM mysql.user WHERE user != 'root';
user plugin authentication_string password
grant_user test_plugin_server plug_dest
-plug_dest NULL *560881EB651416CEF77314D07D55EDCD5FC1BD6D
+plug_dest mysql_native_password *560881EB651416CEF77314D07D55EDCD5FC1BD6D
DROP USER grant_user,plug_dest;
set @@sql_mode= @save_sql_mode;
DROP DATABASE test_user_db;
=== modified file 'mysql-test/r/plugin_auth_qa_1.result'
--- a/mysql-test/r/plugin_auth_qa_1.result 2011-03-18 14:58:27 +0000
+++ b/mysql-test/r/plugin_auth_qa_1.result 2011-05-27 14:40:44 +0000
@@ -21,7 +21,7 @@ GRANT ALL PRIVILEGES ON test_user_db.* T
GRANT PROXY ON plug_dest TO plug_user;
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-plug_dest NULL
+plug_dest mysql_native_password
plug_user test_plugin_server plug_dest
1)
current_user()
@@ -74,7 +74,7 @@ GRANT PROXY ON new_dest TO plug_user;
ERROR 1045 (28000): Access denied for user 'plug_user'@'localhost' (using password: YES)
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-new_dest NULL
+new_dest mysql_native_password
plug_user test_plugin_server plug_dest
DROP USER plug_user,new_dest;
CREATE USER plug_user
@@ -92,7 +92,7 @@ GRANT PROXY ON new_dest TO plug_user;
ERROR 1045 (28000): Access denied for user 'plug_user'@'localhost' (using password: YES)
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-new_dest NULL
+new_dest mysql_native_password
plug_user test_plugin_server plug_dest
DROP USER plug_user,new_dest;
CREATE USER plug_user
@@ -114,13 +114,13 @@ connection default;
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
new_user test_plugin_server plug_dest
-plug_dest NULL
+plug_dest mysql_native_password
disconnect plug_user;
UPDATE mysql.user SET user='plug_user' WHERE user='new_user';
FLUSH PRIVILEGES;
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-plug_dest NULL
+plug_dest mysql_native_password
plug_user test_plugin_server plug_dest
DROP USER plug_dest,plug_user;
========== test 1.3 ========================================
@@ -136,26 +136,26 @@ connection default;
disconnect plug_user;
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-plug_dest NULL
+plug_dest mysql_native_password
plug_user test_plugin_server plug_dest
UPDATE mysql.user SET user='new_user' WHERE user='plug_user';
FLUSH PRIVILEGES;
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
new_user test_plugin_server plug_dest
-plug_dest NULL
+plug_dest mysql_native_password
UPDATE mysql.user SET authentication_string='new_dest' WHERE user='new_user';
FLUSH PRIVILEGES;
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
new_user test_plugin_server new_dest
-plug_dest NULL
+plug_dest mysql_native_password
UPDATE mysql.user SET plugin='new_plugin_server' WHERE user='new_user';
FLUSH PRIVILEGES;
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
new_user new_plugin_server new_dest
-plug_dest NULL
+plug_dest mysql_native_password
connect(plug_user,localhost,new_user,new_dest);
ERROR HY000: Plugin 'new_plugin_server' is not loaded
UPDATE mysql.user SET plugin='test_plugin_server' WHERE user='new_user';
@@ -164,7 +164,7 @@ FLUSH PRIVILEGES;
GRANT PROXY ON new_dest TO new_user;
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-new_dest NULL
+new_dest mysql_native_password
new_user test_plugin_server new_dest
connect(plug_user,localhost,new_user,new_dest);
select USER(),CURRENT_USER();
@@ -177,9 +177,9 @@ FLUSH PRIVILEGES;
CREATE USER new_dest IDENTIFIED BY 'new_dest_passwd';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-new_dest NULL
+new_dest mysql_native_password
new_user test_plugin_server new_dest
-plug_dest NULL
+plug_dest mysql_native_password
GRANT ALL PRIVILEGES ON test.* TO new_user;
connect(plug_user,localhost,new_dest,new_dest_passwd);
select USER(),CURRENT_USER();
@@ -194,7 +194,7 @@ CREATE USER proxied_user IDENTIFIED BY '
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
test_plugin_server proxied_user
-proxied_user NULL
+proxied_user mysql_native_password
connect(proxy_con,localhost,proxied_user,proxied_user_passwd);
SELECT USER(),CURRENT_USER();
USER() CURRENT_USER()
@@ -231,7 +231,7 @@ CREATE USER proxied_user IDENTIFIED BY '
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
test_plugin_server proxied_user
-proxied_user NULL
+proxied_user mysql_native_password
connect(proxy_con,localhost,proxied_user,proxied_user_passwd);
SELECT USER(),CURRENT_USER();
USER() CURRENT_USER()
@@ -274,11 +274,11 @@ GRANT PROXY ON proxied_user_5 TO ''@'';
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
test_plugin_server proxied_user
-proxied_user_1 NULL
-proxied_user_2 NULL
-proxied_user_3 NULL
-proxied_user_4 NULL
-proxied_user_5 NULL
+proxied_user_1 mysql_native_password
+proxied_user_2 mysql_native_password
+proxied_user_3 mysql_native_password
+proxied_user_4 mysql_native_password
+proxied_user_5 mysql_native_password
connect(proxy_con_1,localhost,proxied_user_1,'proxied_user_1_pwd');
connect(proxy_con_2,localhost,proxied_user_2,proxied_user_2_pwd);
connect(proxy_con_3,localhost,proxied_user_3,proxied_user_3_pwd);
=== modified file 'mysql-test/r/plugin_auth_qa_2.result'
--- a/mysql-test/r/plugin_auth_qa_2.result 2011-03-18 14:16:17 +0000
+++ b/mysql-test/r/plugin_auth_qa_2.result 2011-05-27 14:40:44 +0000
@@ -7,7 +7,7 @@ GRANT ALL PRIVILEGES ON test_user_db.* T
GRANT PROXY ON qa_test_1_dest TO qa_test_1_user;
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-qa_test_1_dest NULL
+qa_test_1_dest mysql_native_password
qa_test_1_user qa_auth_interface qa_test_1_dest
SELECT @@proxy_user;
@@proxy_user
@@ -20,7 +20,7 @@ current_user() user() @@local.proxy_user
qa_test_1_user@% qa_test_1_user@localhost NULL NULL
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-qa_test_1_dest NULL
+qa_test_1_dest mysql_native_password
qa_test_1_user qa_auth_interface qa_test_1_dest
DROP USER qa_test_1_user;
DROP USER qa_test_1_dest;
@@ -33,8 +33,8 @@ GRANT PROXY ON qa_test_2_dest TO qa_test
GRANT PROXY ON authenticated_as TO qa_test_2_user;
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-authenticated_as NULL
-qa_test_2_dest NULL
+authenticated_as mysql_native_password
+qa_test_2_dest mysql_native_password
qa_test_2_user qa_auth_interface qa_test_2_dest
SELECT @@proxy_user;
@@proxy_user
@@ -47,8 +47,8 @@ current_user() user() @@local.proxy_user
authenticated_as@% user_name@localhost 'qa_test_2_user'@'%' 'qa_test_2_user'@'%'
SELECT user,plugin,authentication_string FROM mysql.user WHERE user != 'root';
user plugin authentication_string
-authenticated_as NULL
-qa_test_2_dest NULL
+authenticated_as mysql_native_password
+qa_test_2_dest mysql_native_password
qa_test_2_user qa_auth_interface qa_test_2_dest
DROP USER qa_test_2_user;
DROP USER qa_test_2_dest;
@@ -83,8 +83,8 @@ GRANT PROXY ON qa_test_5_dest TO qa_test
GRANT PROXY ON qa_test_5_dest TO ''@'localhost';
SELECT user,plugin,authentication_string,password FROM mysql.user WHERE user != 'root';
user plugin authentication_string password
- NULL *DFCACE76914AD7BD801FC1A1ECF6562272621A22
-qa_test_5_dest NULL *DFCACE76914AD7BD801FC1A1ECF6562272621A22
+ mysql_native_password *DFCACE76914AD7BD801FC1A1ECF6562272621A22
+qa_test_5_dest mysql_native_password *DFCACE76914AD7BD801FC1A1ECF6562272621A22
qa_test_5_user qa_auth_interface qa_test_5_dest
exec MYSQL PLUGIN_AUTH_OPT -h localhost -P MASTER_MYPORT --user=qa_test_5_user --password=qa_test_5_dest test_user_db -e "SELECT current_user(),user(),@@local.proxy_user,@@local.external_user;" 2>&1
ERROR 1045 (28000): Access denied for user 'qa_test_5_user'@'localhost' (using password: YES)
@@ -98,7 +98,7 @@ GRANT ALL PRIVILEGES ON test_user_db.* T
GRANT PROXY ON qa_test_6_dest TO qa_test_6_user;
SELECT user,plugin,authentication_string,password FROM mysql.user;
user plugin authentication_string password
-qa_test_6_dest NULL *DFCACE76914AD7BD801FC1A1ECF6562272621A22
+qa_test_6_dest mysql_native_password *DFCACE76914AD7BD801FC1A1ECF6562272621A22
qa_test_6_user qa_auth_interface qa_test_6_dest
root
root
@@ -109,7 +109,7 @@ ERROR 1045 (28000): Access denied for us
GRANT PROXY ON qa_test_6_dest TO root IDENTIFIED WITH qa_auth_interface AS 'qa_test_6_dest';
SELECT user,plugin,authentication_string,password FROM mysql.user;
user plugin authentication_string password
-qa_test_6_dest NULL *DFCACE76914AD7BD801FC1A1ECF6562272621A22
+qa_test_6_dest mysql_native_password *DFCACE76914AD7BD801FC1A1ECF6562272621A22
qa_test_6_user qa_auth_interface qa_test_6_dest
root
root
@@ -121,7 +121,7 @@ ERROR 1045 (28000): Access denied for us
REVOKE PROXY ON qa_test_6_dest FROM root;
SELECT user,plugin,authentication_string FROM mysql.user;
user plugin authentication_string
-qa_test_6_dest NULL
+qa_test_6_dest mysql_native_password
qa_test_6_user qa_auth_interface qa_test_6_dest
root
root
=== added file 'mysql-test/r/plugin_auth_sha256.result'
--- a/mysql-test/r/plugin_auth_sha256.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/plugin_auth_sha256.result 2011-05-27 14:40:44 +0000
@@ -0,0 +1,38 @@
+CREATE USER 'kristofer' IDENTIFIED WITH 'sha256_password';
+SET @@old_passwords=2;
+SET PASSWORD FOR 'kristofer'=PASSWORD('secret');
+SELECT user, plugin FROM mysql.user;
+user plugin
+root
+root
+root
+root
+kristofer sha256_password
+SELECT USER(),CURRENT_USER();
+USER() CURRENT_USER()
+kristofer@localhost kristofer@%
+DROP USER 'kristofer';
+GRANT ALL ON *.* TO 'kristofer'@'localhost' IDENTIFIED WITH 'sha256_password';
+SET PASSWORD FOR 'kristofer'@'localhost'=PASSWORD('secret2');
+SELECT USER(),CURRENT_USER();
+USER() CURRENT_USER()
+kristofer@localhost kristofer@localhost
+SHOW GRANTS FOR 'kristofer'@'localhost';
+Grants for kristofer@localhost
+GRANT ALL PRIVILEGES ON *.* TO 'kristofer'@'localhost' IDENTIFIED BY PASSWORD '{$5}'
+DROP USER 'kristofer'@'localhost';
+GRANT ALL ON *.* TO 'kristofer'@'localhost' IDENTIFIED WITH 'sha256_password';
+SET PASSWORD FOR 'kristofer'@'localhost'=PASSWORD('');
+SELECT USER(),CURRENT_USER();
+USER() CURRENT_USER()
+kristofer@localhost kristofer@localhost
+SHOW GRANTS FOR 'kristofer'@'localhost';
+Grants for kristofer@localhost
+GRANT ALL PRIVILEGES ON *.* TO 'kristofer'@'localhost' IDENTIFIED BY PASSWORD '{$5}'
+DROP USER 'kristofer'@'localhost';
+GRANT ALL ON *.* TO 'kristofer'@'33.33.33.33' IDENTIFIED WITH 'sha256_password';
+SET PASSWORD FOR 'kristofer'@'33.33.33.33'=PASSWORD('');
+Connection should fail for localhost
+connect(localhost,kristofer,,test,13000,/home/thek/bzr/mysql-trunk-security/build/mysql-test/var/tmp/mysqld.1.sock);
+ERROR 28000: Access denied for user 'kristofer'@'localhost' (using password: NO)
+DROP USER 'kristofer'@'33.33.33.33';
=== modified file 'mysql-test/t/plugin_auth.test'
--- a/mysql-test/t/plugin_auth.test 2011-04-07 09:55:09 +0000
+++ b/mysql-test/t/plugin_auth.test 2011-05-27 14:40:44 +0000
@@ -8,9 +8,7 @@ query_vertical SELECT PLUGIN_STATUS, PLU
CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd';
-
SELECT plugin,authentication_string FROM mysql.user WHERE User='plug';
-
--echo ## test plugin auth
--disable_query_log
--error ER_ACCESS_DENIED_ERROR : this should fail : no grant
@@ -31,6 +29,7 @@ select USER(),CURRENT_USER();
--echo ## test SET PASSWORD
#--error ER_SET_PASSWORD_AUTH_PLUGIN
+--echo Setting password is allowed but it won't affect the authentication mechanism.
SET PASSWORD = PASSWORD('plug_dest');
connection default;
@@ -62,7 +61,6 @@ SET @@sql_mode=no_auto_create_user;
GRANT INSERT ON TEST.* TO grant_user IDENTIFIED WITH 'test_plugin_server';
SET @@sql_mode=default;
DROP USER grant_user;
-
--echo ## test utf-8 user name
CREATE USER `Ÿ` IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
@@ -82,8 +80,7 @@ CREATE DATABASE test_grant_db;
--echo # create new user via GRANT WITH
GRANT ALL PRIVILEGES ON test_grant_db.* TO new_grant_user
- IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
-
+IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
GRANT PROXY ON plug_dest TO new_grant_user;
connect(plug_con_grant,localhost,new_grant_user,plug_dest);
@@ -105,7 +102,6 @@ GRANT ALL PRIVILEGES ON test_grant_db.*
--error ER_ACCESS_DENIED_ERROR
connect(plug_con_grant_deny,localhost,new_grant_user,unused_password);
--enable_query_log
-
--echo #make sure plugin auth still available
connect(plug_con_grant,localhost,new_grant_user,plug_dest);
connection plug_con_grant;
@@ -119,8 +115,8 @@ disconnect plug_con_grant;
DROP USER new_grant_user;
--echo # try re-create existing user via GRANT IDENTIFIED WITH
-
---error ER_GRANT_PLUGIN_USER_EXISTS
+#--error ER_GRANT_PLUGIN_USER_EXISTS
+--echo GRANTS which don't affect current plugin are allowed!
GRANT ALL PRIVILEGES ON test_grant_db.* TO plug
IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
@@ -512,5 +508,4 @@ SELECT IS_NULLABLE, COLUMN_NAME FROM INF
COLUMN_NAME IN ('plugin', 'authentication_string')
ORDER BY COLUMN_NAME;
-
--echo End of 5.5 tests
=== modified file 'mysql-test/t/plugin_auth_qa.test'
--- a/mysql-test/t/plugin_auth_qa.test 2010-10-20 14:56:09 +0000
+++ b/mysql-test/t/plugin_auth_qa.test 2011-05-27 14:40:44 +0000
@@ -166,9 +166,11 @@ SELECT user,plugin,authentication_string
DROP USER plug_dest;
#
CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
---error 1700
+#--error 1700
+--echo GRANTs which doesn't change the plugin are allowed
GRANT ALL PRIVILEGES ON test_user_db.* TO plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
---error 1700
+#--error 1700
+--echo GRANTs which doesn't change the plugin are allowed
GRANT ALL PRIVILEGES ON test_user_db.* TO plug IDENTIFIED WITH 'test_plugin_server';
DROP USER plug;
#
=== added file 'mysql-test/t/plugin_auth_sha256.test'
--- a/mysql-test/t/plugin_auth_sha256.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/plugin_auth_sha256.test 2011-05-27 14:40:44 +0000
@@ -0,0 +1,41 @@
+--source include/not_embedded.inc
+--source include/mysql_upgrade_preparation.inc
+
+CREATE USER 'kristofer' IDENTIFIED WITH 'sha256_password';
+SET @@old_passwords=2;
+SET PASSWORD FOR 'kristofer'=PASSWORD('secret');
+SELECT user, plugin FROM mysql.user;
+connect(con1,localhost,kristofer,secret,,);
+connection con1;
+SELECT USER(),CURRENT_USER();
+connection default;
+disconnect con1;
+DROP USER 'kristofer';
+
+GRANT ALL ON *.* TO 'kristofer'@'localhost' IDENTIFIED WITH 'sha256_password';
+SET PASSWORD FOR 'kristofer'@'localhost'=PASSWORD('secret2');
+connect(con2,localhost,kristofer,secret2,,);
+connection con2;
+SELECT USER(),CURRENT_USER();
+SHOW GRANTS FOR 'kristofer'@'localhost';
+connection default;
+disconnect con2;
+DROP USER 'kristofer'@'localhost';
+
+GRANT ALL ON *.* TO 'kristofer'@'localhost' IDENTIFIED WITH 'sha256_password';
+SET PASSWORD FOR 'kristofer'@'localhost'=PASSWORD('');
+connect(con3,localhost,kristofer,,,);
+connection con3;
+SELECT USER(),CURRENT_USER();
+SHOW GRANTS FOR 'kristofer'@'localhost';
+connection default;
+disconnect con3;
+DROP USER 'kristofer'@'localhost';
+
+GRANT ALL ON *.* TO 'kristofer'@'33.33.33.33' IDENTIFIED WITH 'sha256_password';
+SET PASSWORD FOR 'kristofer'@'33.33.33.33'=PASSWORD('');
+--echo Connection should fail for localhost
+--error ER_ACCESS_DENIED_ERROR
+connect(con4,localhost,kristofer,,,);
+DROP USER 'kristofer'@'33.33.33.33';
+
=== modified file 'scripts/mysql_system_tables.sql'
--- a/scripts/mysql_system_tables.sql 2011-03-18 22:51:17 +0000
+++ b/scripts/mysql_system_tables.sql 2011-05-27 14:40:44 +0000
@@ -28,7 +28,7 @@ set @had_db_table= @@warning_count != 0;
CREATE TABLE IF NOT EXISTS host ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY Host (Host,Db) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Host privileges; Merged with database privileges';
-CREATE TABLE IF NOT EXISTS user ( Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Reload_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Shutdown_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Process_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, File_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_db_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Super_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tablespace_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL, ssl_cipher BLOB NOT NULL, x509_issuer BLOB NOT NULL, x509_subject BLOB NOT NULL, max_questions int(11) unsigned DEFAULT 0 NOT NULL, max_updates int(11) unsigned DEFAULT 0 NOT NULL, max_connections int(11) unsigned DEFAULT 0 NOT NULL, max_user_connections int(11) unsigned DEFAULT 0 NOT NULL, plugin char(64) DEFAULT '', authentication_string TEXT, PRIMARY KEY Host (Host,User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges';
+CREATE TABLE IF NOT EXISTS user ( Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Reload_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Shutdown_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Process_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, File_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_db_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Super_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tablespace_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL, ssl_cipher BLOB NOT NULL, x509_issuer BLOB NOT NULL, x509_subject BLOB NOT NULL, max_questions int(11) unsigned DEFAULT 0 NOT NULL, max_updates int(11) unsigned DEFAULT 0 NOT NULL, max_connections int(11) unsigned DEFAULT 0 NOT NULL, max_user_connections int(11) unsigned DEFAULT 0 NOT NULL, plugin char(64) DEFAULT '', authentication_string TEXT, Password2 VARCHAR(80) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, PRIMARY KEY Host (Host,User)) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges';
-- Remember for later if user table already existed
set @had_user_table= @@warning_count != 0;
=== modified file 'scripts/mysql_system_tables_data.sql'
--- a/scripts/mysql_system_tables_data.sql 2010-12-29 00:38:59 +0000
+++ b/scripts/mysql_system_tables_data.sql 2011-05-27 14:40:44 +0000
@@ -36,10 +36,10 @@ DROP TABLE tmp_db;
-- from local machine if "users" table didn't exist before
CREATE TEMPORARY TABLE tmp_user LIKE user;
set @current_hostname= @@hostname;
-INSERT INTO tmp_user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','');
-REPLACE INTO tmp_user SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','' FROM dual WHERE LOWER( @current_hostname) != 'localhost';
-REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','');
-REPLACE INTO tmp_user VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','');
+INSERT INTO tmp_user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','');
+REPLACE INTO tmp_user SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','' FROM dual WHERE LOWER( @current_hostname) != 'localhost';
+REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','');
+REPLACE INTO tmp_user VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','');
INSERT INTO tmp_user (host,user) VALUES ('localhost','');
INSERT INTO tmp_user (host,user) SELECT @current_hostname,'' FROM dual WHERE LOWER(@current_hostname ) != 'localhost';
INSERT INTO user SELECT * FROM tmp_user WHERE @had_user_table=0;
=== modified file 'sql-common/client.c'
--- a/sql-common/client.c 2011-03-17 09:43:28 +0000
+++ b/sql-common/client.c 2011-05-27 14:40:44 +0000
@@ -36,6 +36,7 @@
#include <my_global.h>
#include "mysql.h"
+#include "crypt_genhash_impl.h"
#ifndef __WIN__
#include <netdb.h>
@@ -2271,6 +2272,7 @@ static int client_mpvio_write_packet(str
static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
+static int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
static auth_plugin_t native_password_client_plugin=
{
@@ -2320,11 +2322,28 @@ static auth_plugin_t clear_password_clie
clear_password_auth_client
};
+static auth_plugin_t sha256_password_client_plugin=
+{
+ MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
+ MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
+ "sha256_password",
+ "Oracle Inc",
+ "SHA256 based authentication with salt",
+ {1, 0, 0},
+ "GPL",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ sha256_password_auth_client
+};
+
struct st_mysql_client_plugin *mysql_client_builtins[]=
{
(struct st_mysql_client_plugin *)&native_password_client_plugin,
(struct st_mysql_client_plugin *)&old_password_client_plugin,
(struct st_mysql_client_plugin *)&clear_password_client_plugin,
+ (struct st_mysql_client_plugin *)&sha256_password_client_plugin,
0
};
@@ -4411,4 +4430,88 @@ static int clear_password_auth_client(MY
return res ? CR_ERROR : CR_OK;
}
+static int sha256_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ int pkt_len;
+ uchar *pkt;
+ const char *one_round_params[2]= {"rounds=1", 0 };
+ my_bool uses_passwords;
+
+ uses_passwords= mysql->passwd[0] != 0;
+
+ DBUG_ENTER("sha256_password_auth_client");
+
+ if (((MCPVIO_EXT *)vio)->mysql_change_user)
+ {
+ /*
+ in mysql_change_user() the client sends the first packet.
+ we use the old scramble.
+ */
+ pkt= (uchar*)mysql->scramble;
+ pkt_len= SCRAMBLE_LENGTH + 1;
+ }
+ else
+ {
+ /* read the scramble */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+ DBUG_RETURN(CR_ERROR);
+
+ if (pkt_len != SCRAMBLE_LENGTH + 1)
+ DBUG_RETURN(CR_SERVER_HANDSHAKE_ERR);
+
+ /* save it in MYSQL */
+ memcpy(mysql->scramble, pkt, SCRAMBLE_LENGTH);
+ mysql->scramble[SCRAMBLE_LENGTH] = 0;
+ }
+
+ /* Send package to request user salt */
+ if (vio->write_packet(vio, (uchar*)&uses_passwords,1))
+ DBUG_RETURN(CR_ERROR);
+
+ /*
+ If no password is used the server got all information it needs and the
+ plugin authentication process is done. Authentication will fail if the
+ network address of the client doesn't match server host restrictions.
+ */
+ if (!uses_passwords)
+ DBUG_RETURN(CR_OK);
+
+ /* Receive user salt */
+ unsigned length;
+ if ((length= vio->read_packet(vio, &pkt)) < 0)
+ DBUG_RETURN(CR_ERROR);
+
+ /* Validate salt */
+ length= ((length < (CRYPT_SALT_LENGTH)) ?
+ length : (CRYPT_SALT_LENGTH));
+ char user_salt[CRYPT_SALT_LENGTH+1];
+ memcpy(user_salt, pkt, length);
+ user_salt[length]= 0;
+
+ /* Generate password hash */
+ char scrambled[CRYPT_MAX_PASSWORD_SIZE+1];
+ char scrambled_random[CRYPT_MAX_PASSWORD_SIZE+1];
+ int passwd_len= strlen(mysql->passwd);
+ DBUG_PRINT("info", ("sending scramble"));
+ crypt_genhash_impl(scrambled,
+ CRYPT_MAX_PASSWORD_SIZE,
+ mysql->passwd,
+ passwd_len,
+ user_salt,
+ 0);
+ int scrambled_len= strlen(scrambled);
+ crypt_genhash_impl(scrambled_random,
+ CRYPT_MAX_PASSWORD_SIZE,
+ scrambled,
+ scrambled_len,
+ mysql->scramble,
+ one_round_params);
+ if (vio->write_packet(vio, (uchar*)scrambled_random,
+ strlen(scrambled_random)))
+ DBUG_RETURN(CR_ERROR);
+
+ DBUG_RETURN(CR_OK);
+}
+
+
=== added file 'sql-common/crypt_genhash_impl.cc'
--- a/sql-common/crypt_genhash_impl.cc 1970-01-01 00:00:00 +0000
+++ b/sql-common/crypt_genhash_impl.cc 2011-05-27 14:40:44 +0000
@@ -0,0 +1,423 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_OPENSSL
+#ifdef HAVE_YASSL
+#include <sha.hpp>
+#else
+#include <sys/types.h>
+#include <openssl/sha.h>
+#endif
+#endif
+
+#include "crypt_genhash_impl.h"
+
+#ifndef HAVE_YASSL
+#define DIGEST_CTX SHA256_CTX
+#define DIGESTInit SHA256_Init
+#define DIGESTUpdate SHA256_Update
+#define DIGESTFinal SHA256_Final
+#define DIGEST_LEN SHA256_DIGEST_LENGTH
+#else
+#define DIGEST_CTX TaoCrypt::SHA256
+#define DIGEST_LEN 32
+void DIGESTInit(DIGEST_CTX *ctx)
+{
+ ctx->Init();
+}
+
+void DIGESTUpdate(DIGEST_CTX *ctx, const void *plaintext, int len)
+{
+ ctx->Update((const TaoCrypt::byte *)plaintext, len);
+}
+
+void DIGESTFinal(void *txt, DIGEST_CTX *ctx)
+{
+ ctx->Final((TaoCrypt::byte *)txt);
+}
+
+#endif // HAVE_YASSL
+
+static const char crypt_alg_magic[] = "$5";
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef B_FALSE
+#define B_FALSE 0
+#endif
+#ifndef B_TRUE
+#define B_TRUE 1
+#endif
+
+
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+ char *d= dst;
+ const char *s= src;
+ size_t n= siz;
+ size_t dlen;
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen= d - dst;
+ n= siz - dlen;
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0')
+ {
+ if (n != 1)
+ {
+ *d++= *s;
+ n--;
+ }
+ s++;
+ }
+ *d= '\0';
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
+static const int crypt_alg_magic_len = sizeof (crypt_alg_magic) - 1;
+
+static unsigned char b64t[] = /* 0 ... 63 => ascii - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+#define b64_from_24bit(B2, B1, B0, N) \
+{ \
+ uint32_t w = ((B2) << 16) | ((B1) << 8) | (B0); \
+ int n = (N); \
+ while (--n >= 0 && ctbufflen > 0) { \
+ *p++ = b64t[w & 0x3f]; \
+ w >>= 6; \
+ ctbufflen--; \
+} \
+}
+
+#define ROUNDS "rounds="
+#define ROUNDSLEN (sizeof (ROUNDS) - 1)
+
+typedef bool boolean_t;
+
+/**
+ Get the integer value after rounds= where ever it occurs in the string.
+ if the last char after the int is a , or $ that is fine anything else is an
+ error.
+*/
+static uint getrounds(const char *s)
+{
+ const char *r;
+ const char *p;
+ char *e;
+ long val;
+
+ if (s == NULL)
+ return (0);
+
+ if ((r = strstr(s, ROUNDS)) == NULL)
+ {
+ return (0);
+ }
+
+ if (strncmp(r, ROUNDS, ROUNDSLEN) != 0)
+ {
+ return (0);
+ }
+
+ p = r + ROUNDSLEN;
+ errno= 0;
+ val = strtol(p, &e, 10);
+ /*
+ * An error occurred or there is non-numeric stuff at the end
+ * which isn't one of the crypt(3c) special chars ',' or '$'
+ */
+ if (errno != 0 || val < 0 || !(*e == '\0' || *e == ',' || *e == '$'))
+ {
+ return (0);
+ }
+
+ return ((uint32_t)val);
+}
+
+/**
+ Finds the intervall which envelopes the user salt in a crypt password
+ The crypt format is assumed to be $a$bbbb$cccccc\0 and the salt is found
+ by counting the delimiters and marking begin and end.
+
+ @param salt_being[in] Pointer to start of crypt passwd
+ @param salt_being[out] Pointer to first byte of the salt
+ @param salt_end[in] Pointer to the last byte in passwd
+ @param salt_end[out] Pointer to the byte immediatly following the salt ($)
+
+ @return The size of the salt identified
+*/
+
+int extract_user_salt(char **salt_begin,
+ char **salt_end)
+{
+ char *it= *salt_begin;
+ int delimiter_count= 0;
+ while(it != *salt_end)
+ {
+ if (*it == '$')
+ {
+ ++delimiter_count;
+ if (delimiter_count == 2)
+ {
+ *salt_begin= it+1;
+ }
+ if (delimiter_count == 3)
+ break;
+ }
+ ++it;
+ }
+ *salt_end= it;
+ return *salt_end - *salt_begin;
+}
+
+const char *sha256_find_digest(char *pass)
+{
+ int sz= strlen(pass);
+ return pass+sz-(10*4+3);
+}
+
+/*
+ * Portions of the below code come from crypt_bsdmd5.so (bsdmd5.c) :
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@strippedt.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $
+ *
+ */
+
+/*
+ * The below code implements the specification from:
+ *
+ * From http://people.redhat.com/drepper/SHA-crypt.txt
+ *
+ * Portions of the code taken from inspired by or verified against the
+ * source in the above document which is licensed as:
+ *
+ * "Released into the Public Domain by Ulrich Drepper <drepper@stripped>."
+ */
+
+/* ARGSUSED4 */
+extern "C"
+char *
+crypt_genhash_impl(char *ctbuffer,
+ size_t ctbufflen,
+ const char *plaintext,
+ int plaintext_len,
+ const char *switchsalt,
+ const char **params)
+{
+ int salt_len, i;
+ char *salt;
+ unsigned char A[DIGEST_LEN];
+ unsigned char B[DIGEST_LEN];
+ unsigned char DP[DIGEST_LEN];
+ unsigned char DS[DIGEST_LEN];
+ DIGEST_CTX ctxA, ctxB, ctxC, ctxDP, ctxDS;
+ int rounds = ROUNDS_DEFAULT;
+ int srounds = 0;
+ boolean_t custom_rounds = B_FALSE;
+ char *p;
+ char *P, *Pp;
+ char *S, *Sp;
+
+ /* Refine the salt */
+ salt = (char *)switchsalt;
+
+ /* skip our magic string */
+ if (strncmp((char *)salt, crypt_alg_magic, crypt_alg_magic_len) == 0)
+ {
+ salt += crypt_alg_magic_len + 1;
+ }
+
+ srounds = getrounds(salt);
+ if (srounds != 0) {
+ rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX));
+ custom_rounds = B_TRUE;
+ p = strchr(salt, '$');
+ if (p != NULL)
+ salt = p + 1;
+ }
+
+ salt_len = MIN(strcspn(salt, "$"), CRYPT_SALT_LENGTH);
+ //plaintext_len = strlen(plaintext);
+
+ /* 1. */
+ DIGESTInit(&ctxA);
+
+ /* 2. The password first, since that is what is most unknown */
+ DIGESTUpdate(&ctxA, plaintext, plaintext_len);
+
+ /* 3. Then the raw salt */
+ DIGESTUpdate(&ctxA, salt, salt_len);
+
+ /* 4. - 8. */
+ DIGESTInit(&ctxB);
+ DIGESTUpdate(&ctxB, plaintext, plaintext_len);
+ DIGESTUpdate(&ctxB, salt, salt_len);
+ DIGESTUpdate(&ctxB, plaintext, plaintext_len);
+ DIGESTFinal(B, &ctxB);
+
+ /* 9. - 10. */
+ for (i= plaintext_len; i > MIXCHARS; i -= MIXCHARS)
+ DIGESTUpdate(&ctxA, B, MIXCHARS);
+ DIGESTUpdate(&ctxA, B, i);
+
+ /* 11. */
+ for (i= plaintext_len; i > 0; i >>= 1) {
+ if ((i & 1) != 0)
+ {
+ DIGESTUpdate(&ctxA, B, MIXCHARS);
+ }
+ else
+ {
+ DIGESTUpdate(&ctxA, plaintext, plaintext_len);
+ }
+ }
+
+ /* 12. */
+ DIGESTFinal(A, &ctxA);
+
+ /* 13. - 15. */
+ DIGESTInit(&ctxDP);
+ for (i= 0; i < plaintext_len; i++)
+ DIGESTUpdate(&ctxDP, plaintext, plaintext_len);
+ DIGESTFinal(DP, &ctxDP);
+
+ /* 16. */
+ Pp= P= (char *)alloca(plaintext_len);
+ for (i= plaintext_len; i >= MIXCHARS; i -= MIXCHARS)
+ {
+ Pp= (char *)(memcpy(Pp, DP, MIXCHARS)) + MIXCHARS;
+ }
+ (void) memcpy(Pp, DP, i);
+
+ /* 17. - 19. */
+ DIGESTInit(&ctxDS);
+ for (i= 0; i < 16 + (uint8_t)A[0]; i++)
+ DIGESTUpdate(&ctxDS, salt, salt_len);
+ DIGESTFinal(DS, &ctxDS);
+
+ /* 20. */
+ Sp= S= (char *)alloca(salt_len);
+ for (i= salt_len; i >= MIXCHARS; i -= MIXCHARS)
+ {
+ Sp= (char *)(memcpy(Sp, DS, MIXCHARS)) + MIXCHARS;
+ }
+ (void) memcpy(Sp, DS, i);
+
+ /* 21. */
+ for (i= 0; i < rounds; i++)
+ {
+ DIGESTInit(&ctxC);
+
+ if ((i & 1) != 0)
+ {
+ DIGESTUpdate(&ctxC, P, plaintext_len);
+ }
+ else
+ {
+ if (i == 0)
+ DIGESTUpdate(&ctxC, A, MIXCHARS);
+ else
+ DIGESTUpdate(&ctxC, DP, MIXCHARS);
+ }
+
+ if (i % 3 != 0) {
+ DIGESTUpdate(&ctxC, S, salt_len);
+ }
+
+ if (i % 7 != 0) {
+ DIGESTUpdate(&ctxC, P, plaintext_len);
+ }
+
+ if ((i & 1) != 0)
+ {
+ if (i == 0)
+ DIGESTUpdate(&ctxC, A, MIXCHARS);
+ else
+ DIGESTUpdate(&ctxC, DP, MIXCHARS);
+ }
+ else
+ {
+ DIGESTUpdate(&ctxC, P, plaintext_len);
+ }
+ DIGESTFinal(DP, &ctxC);
+ }
+
+ /* 22. Now make the output string */
+ if (custom_rounds)
+ {
+ (void) snprintf(ctbuffer, ctbufflen,
+ "%s$rounds=%zu$", crypt_alg_magic, (size_t)rounds);
+ }
+ else
+ {
+ (void) snprintf(ctbuffer, ctbufflen,
+ "%s$", crypt_alg_magic);
+ }
+ (void) strncat(ctbuffer, (const char *)salt, salt_len);
+ (void) strlcat(ctbuffer, "$", ctbufflen);
+
+ p= ctbuffer + strlen(ctbuffer);
+ ctbufflen -= strlen(ctbuffer);
+
+ b64_from_24bit(DP[ 0], DP[10], DP[20], 4);
+ b64_from_24bit(DP[21], DP[ 1], DP[11], 4);
+ b64_from_24bit(DP[12], DP[22], DP[ 2], 4);
+ b64_from_24bit(DP[ 3], DP[13], DP[23], 4);
+ b64_from_24bit(DP[24], DP[ 4], DP[14], 4);
+ b64_from_24bit(DP[15], DP[25], DP[ 5], 4);
+ b64_from_24bit(DP[ 6], DP[16], DP[26], 4);
+ b64_from_24bit(DP[27], DP[ 7], DP[17], 4);
+ b64_from_24bit(DP[18], DP[28], DP[ 8], 4);
+ b64_from_24bit(DP[ 9], DP[19], DP[29], 4);
+ b64_from_24bit(0, DP[31], DP[30], 3);
+ *p= '\0';
+
+ (void) memset(A, 0, sizeof (A));
+ (void) memset(B, 0, sizeof (B));
+ (void) memset(DP, 0, sizeof (DP));
+ (void) memset(DS, 0, sizeof (DS));
+
+ return (ctbuffer);
+}
+
+
+/**
+ Generate a random string using ASCII characters but avoid seperator character.
+ Stdlib rand and srand are used to produce pseudo random numbers between
+ 33 and 126 which corresponds to the following characters:
+ !"#%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
+*/
+extern "C"
+void generate_user_salt(char *buffer, int buffer_len)
+{
+ srand((unsigned)time(NULL));
+ char *end= buffer + buffer_len;
+ /* Use pointer arithmetics as it is faster way to do so. */
+ for (; buffer < end; buffer++)
+ {
+ do
+ {
+ int ch= 33 + (int) (93.0 * (rand() / (RAND_MAX + 1.0)));
+ *buffer= (char) ch;
+ } while (*buffer == '$');
+ }
+ *buffer= '\0';
+}
+
=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt 2011-02-02 08:30:13 +0000
+++ b/sql/CMakeLists.txt 2011-05-27 14:40:44 +0000
@@ -77,6 +77,7 @@ SET(SQL_SHARED_SOURCES
parse_file.cc
partition_info.cc
password.c
+ ../sql-common/crypt_genhash_impl.cc
procedure.cc
protocol.cc
records.cc
=== modified file 'sql/item_strfunc.cc'
--- a/sql/item_strfunc.cc 2011-04-08 13:41:38 +0000
+++ b/sql/item_strfunc.cc 2011-05-27 14:40:44 +0000
@@ -43,6 +43,7 @@
#include "des_key_file.h" // st_des_keyschedule, st_des_keyblock
#include "password.h" // my_make_scrambled_password,
// my_make_scrambled_password_323
+#include "crypt_genhash_impl.h"
#include <m_ctype.h>
#include <base64.h>
#include "my_md5.h"
@@ -1920,22 +1921,69 @@ void Item_func_trim::print(String *str,
String *Item_func_password::val_str_ascii(String *str)
{
DBUG_ASSERT(fixed == 1);
+
+ /* args[0] is the clear text password */
String *res= args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
if (res->length() == 0)
return make_empty_result();
- my_make_scrambled_password(tmp_value, res->ptr(), res->length());
- str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1);
+ /*
+ The value of an Item my be invariant and thus the value cannot change
+ after consequtive calls to this method. This is guaranteed by only
+ hashing the password once and then saving it in a buffer.
+
+ The hashing algorithm is chosen based on the @@old_passwords variable.
+ */
+ if (m_hashed_password_buffer_len == 0 )
+ {
+ THD *thd= current_thd;
+ if (thd->variables.old_passwords == 2)
+ {
+ my_make_scrambled_password(m_hashed_password_buffer, res->ptr(),
+ res->length());
+ m_hashed_password_buffer_len= strlen(m_hashed_password_buffer)+1;
+ }
+ else
+ if (thd->variables.old_passwords == 0)
+ {
+ my_make_scrambled_password_sha1(m_hashed_password_buffer, res->ptr(),
+ res->length());
+ m_hashed_password_buffer_len= SCRAMBLED_PASSWORD_CHAR_LENGTH;
+ }
+ else
+ if (thd->variables.old_passwords == 1)
+ {
+ my_make_scrambled_password_323(m_hashed_password_buffer, res->ptr(),
+ res->length());
+ m_hashed_password_buffer_len= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ }
+
+ /* remove the clear text password */
+ res->fill(CRYPT_MAX_PASSWORD_SIZE, 'X');
+ }
+
+ str->set(m_hashed_password_buffer, m_hashed_password_buffer_len,
+ &my_charset_latin1);
+
return str;
}
-char *Item_func_password::alloc(THD *thd, const char *password,
- size_t pass_len)
+char *Item_func_password::
+ create_password_hash_buffer(THD *thd, const char *password, size_t pass_len)
{
- char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
- if (buff)
+ char *buff= NULL;
+ if (thd->variables.old_passwords == 0)
+ {
+ buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH);
+ my_make_scrambled_password_sha1(buff, password, pass_len);
+ }
+ else
+ {
+ buff= (char *) thd->alloc(CRYPT_MAX_PASSWORD_SIZE+1);
my_make_scrambled_password(buff, password, pass_len);
+ }
+
return buff;
}
=== modified file 'sql/item_strfunc.h'
--- a/sql/item_strfunc.h 2011-03-22 11:44:40 +0000
+++ b/sql/item_strfunc.h 2011-05-27 14:40:44 +0000
@@ -18,6 +18,7 @@
/* This file defines all string functions */
+#include "crypt_genhash_impl.h"
class MY_LOCALE;
@@ -319,16 +320,26 @@ public:
class Item_func_password :public Item_str_ascii_func
{
- char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
+ char m_hashed_password_buffer[CRYPT_MAX_PASSWORD_SIZE+1];
+ unsigned int m_hashed_password_buffer_len;
public:
- Item_func_password(Item *a) :Item_str_ascii_func(a) {}
+ Item_func_password(Item *a) :Item_str_ascii_func(a)
+ {
+ m_hashed_password_buffer_len= 0;
+ }
String *val_str_ascii(String *str);
void fix_length_and_dec()
{
- fix_length_and_charset(SCRAMBLED_PASSWORD_CHAR_LENGTH, default_charset());
+ /*
+ The Item_func_password is an AST component for clear text passwords.
+ The item representation is a result of a hash transformation and the
+ original untransformed value is censored for security reasons.
+ */
+ fix_length_and_charset(MAX_PASSWORD_LENGTH, default_charset());
}
const char *func_name() const { return "password"; }
- static char *alloc(THD *thd, const char *password, size_t pass_len);
+ static char *create_password_hash_buffer(THD *thd, const char *password,
+ size_t pass_len);
};
=== modified file 'sql/password.c'
--- a/sql/password.c 2010-08-09 08:32:50 +0000
+++ b/sql/password.c 2011-05-27 14:40:44 +0000
@@ -64,6 +64,7 @@
#include <m_string.h>
#include <sha1.h>
#include "mysql.h"
+#include "crypt_genhash_impl.h"
/************ MySQL 3.23-4.0 authentication routines: untouched ***********/
@@ -395,6 +396,19 @@ my_crypt(char *to, const uchar *s1, cons
*to++= *s1++ ^ *s2++;
}
+void my_make_scrambled_password(char *to, const char *password,
+ size_t pass_len)
+{
+ char salt[CRYPT_SALT_LENGTH+1];
+
+ generate_user_salt(salt, CRYPT_SALT_LENGTH+1);
+ crypt_genhash_impl(to,
+ CRYPT_MAX_PASSWORD_SIZE,
+ password,
+ pass_len,
+ salt,
+ 0);
+}
/*
MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice
@@ -403,14 +417,14 @@ my_crypt(char *to, const uchar *s1, cons
The result of this function is used as return value from PASSWORD() and
is stored in the database.
SYNOPSIS
- my_make_scrambled_password()
+ my_make_scrambled_password_sha1()
buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string
password IN password string
pass_len IN length of password string
*/
-void my_make_scrambled_password(char *to, const char *password,
- size_t pass_len)
+void my_make_scrambled_password_sha1(char *to, const char *password,
+ size_t pass_len)
{
SHA1_CONTEXT sha1_context;
uint8 hash_stage2[SHA1_HASH_SIZE];
@@ -496,7 +510,7 @@ scramble(char *to, const char *message,
null-terminated, reply and hash_stage2 must be at least SHA1_HASH_SIZE
long (if not, something fishy is going on).
SYNOPSIS
- check_scramble()
+ check_scramble_sha1()
scramble clients' reply, presumably produced by scramble()
message original random string, previously sent to client
(presumably second argument of scramble()), must be
@@ -510,8 +524,8 @@ scramble(char *to, const char *message,
*/
my_bool
-check_scramble(const uchar *scramble_arg, const char *message,
- const uint8 *hash_stage2)
+check_scramble_sha1(const uchar *scramble_arg, const char *message,
+ const uint8 *hash_stage2)
{
SHA1_CONTEXT sha1_context;
uint8 buf[SHA1_HASH_SIZE];
@@ -531,6 +545,12 @@ check_scramble(const uchar *scramble_arg
return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
}
+my_bool
+check_scramble(const uchar *scramble_arg, const char *message,
+ const uint8 *hash_stage2)
+{
+ return check_scramble_sha1(scramble_arg, message, hash_stage2);
+}
/*
Convert scrambled password from asciiz hex string to binary form.
@@ -560,3 +580,4 @@ void make_password_from_salt(char *to, c
*to++= PVERSION41_CHAR;
octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE);
}
+
=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc 2011-03-25 14:35:13 +0000
+++ b/sql/set_var.cc 2011-05-27 14:40:44 +0000
@@ -738,7 +738,7 @@ int set_var_password::check(THD *thd)
user->host.length= 1;
}
}
- if (!user->user.str)
+ if (user->user.length == 0)
{
DBUG_ASSERT(thd->security_ctx->user);
user->user.str= (char *) thd->security_ctx->user;
=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc 2011-04-07 12:04:22 +0000
+++ b/sql/sql_acl.cc 2011-05-27 14:40:44 +0000
@@ -49,8 +49,12 @@
#include "sql_connect.h"
#include "hostname.h"
#include "sql_db.h"
+#include "password.h"
+#include "crypt_genhash_impl.h"
bool mysql_user_table_is_in_short_password_format= false;
+inline bool auth_plugin_is_built_in(const char *plugin_name);
+void optimize_plugin_compare_by_pointer(LEX_STRING *plugin_name);
static const
TABLE_FIELD_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = {
@@ -166,9 +170,226 @@ TABLE_FIELD_TYPE mysql_db_table_fields[M
}
};
+static const
+TABLE_FIELD_TYPE mysql_user_table_fields[MYSQL_USER_FIELD_COUNT] = {
+ {
+ { C_STRING_WITH_LEN("Host") },
+ { C_STRING_WITH_LEN("char(60)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("User") },
+ { C_STRING_WITH_LEN("char(16)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("Password") },
+ { C_STRING_WITH_LEN("char(41)") },
+ { C_STRING_WITH_LEN("latin1") }
+ },
+ {
+ { C_STRING_WITH_LEN("Select_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Insert_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Update_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Delete_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Create_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Drop_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Reload_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Shutdown_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Process_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("File_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Grant_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("References_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Index_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Alter_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Show_db_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Super_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Create_tmp_table_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Lock_tables_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Execute_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Repl_slave_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Repl_client_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Create_view_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Show_view_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Create_routine_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Alter_routine_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Create_user_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Event_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Trigger_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Create_tablespace_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("ssl_type") },
+ { C_STRING_WITH_LEN("enum('','ANY','X509','SPECIFIED')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("ssl_cipher") },
+ { C_STRING_WITH_LEN("blob") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("x509_issuer") },
+ { C_STRING_WITH_LEN("blob") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("x509_subject") },
+ { C_STRING_WITH_LEN("blob") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("max_questions") },
+ { C_STRING_WITH_LEN("int(11)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("max_updates") },
+ { C_STRING_WITH_LEN("int(11)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("max_connections") },
+ { C_STRING_WITH_LEN("int(11)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("plugin") },
+ { C_STRING_WITH_LEN("char(64)") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("authentication_string") },
+ { C_STRING_WITH_LEN("text") },
+ { NULL, 0 }
+ },
+ {
+ { C_STRING_WITH_LEN("Password2") },
+ { C_STRING_WITH_LEN("varchar(80)") },
+ { NULL, 0 }
+ }
+};
+
const TABLE_FIELD_DEF
mysql_db_table_def= {MYSQL_DB_FIELD_COUNT, mysql_db_table_fields};
+const TABLE_FIELD_DEF
+ mysql_user_table_def= {MYSQL_USER_FIELD_COUNT, mysql_user_table_fields};
+
static LEX_STRING native_password_plugin_name= {
C_STRING_WITH_LEN("mysql_native_password")
};
@@ -176,9 +397,14 @@ static LEX_STRING native_password_plugin
static LEX_STRING old_password_plugin_name= {
C_STRING_WITH_LEN("mysql_old_password")
};
+
+LEX_STRING sha256_password_plugin_name= {
+ C_STRING_WITH_LEN("sha256_password")
+};
/// @todo make it configurable
LEX_STRING *default_auth_plugin_name= &native_password_plugin_name;
+//LEX_STRING *default_auth_plugin_name= &sha256_password_plugin_name;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
static plugin_ref old_password_plugin;
@@ -215,8 +441,17 @@ public:
uint hostname_length;
USER_RESOURCES user_resource;
char *user;
+ /**
+ The salt variable is used as the password hash for
+ native_password_authetication and old_password_authentication.
+ */
uint8 salt[SCRAMBLE_LENGTH + 1]; // scrambled password in binary form
- uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 4.0, 20 - 4.1.1
+ /**
+ In the old protocol the salt_len indicated what type of autnetication
+ protocol was used: 0 - no password, 4 - 3.20, 8 - 4.0, 20 - 4.1.1
+ */
+ uint8 salt_len;
+ uint8 sha2_hash[CRYPT_MAX_PASSWORD_SIZE+1];
enum SSL_type ssl_type;
const char *ssl_cipher, *x509_issuer, *x509_subject;
LEX_STRING plugin;
@@ -232,11 +467,17 @@ public:
dst->ssl_cipher= safe_strdup_root(root, ssl_cipher);
dst->x509_issuer= safe_strdup_root(root, x509_issuer);
dst->x509_subject= safe_strdup_root(root, x509_subject);
- if (plugin.str == native_password_plugin_name.str ||
- plugin.str == old_password_plugin_name.str)
+ /*
+ If the plugin is built in we don't need to reallocate the name of the
+ plugin.
+ */
+ if (auth_plugin_is_built_in(dst->plugin.str))
dst->plugin= plugin;
else
+ {
dst->plugin.str= strmake_root(root, plugin.str, plugin.length);
+ dst->plugin.length= plugin.length;
+ }
dst->auth_string.str= safe_strdup_root(root, auth_string.str);
dst->host.hostname= safe_strdup_root(root, host.hostname);
return dst;
@@ -259,6 +500,7 @@ static bool compare_hostname(const acl_h
static bool show_proxy_grants (THD *thd, LEX_USER *user,
char *buff, size_t buffsize);
+
class ACL_PROXY_USER :public ACL_ACCESS
{
acl_host_and_ip host;
@@ -553,22 +795,30 @@ static void init_check_host(void);
static void rebuild_check_host(void);
static ACL_USER *find_acl_user(const char *host, const char *user,
my_bool exact);
-static bool update_user_table(THD *thd, TABLE *table,
- const char *host, const char *user,
- const char *new_password, uint new_password_len);
+static bool update_user_table(TABLE *table, const char *host, const char *user,
+ const char *new_password, uint new_password_len,
+ enum mysql_user_table_field password_field);
static my_bool acl_load(THD *thd, TABLE_LIST *tables);
static my_bool grant_load(THD *thd, TABLE_LIST *tables);
static inline void get_grantor(THD *thd, char* grantor);
-/*
+/**
Convert scrambled password to binary form, according to scramble type,
Binary form is stored in user.salt.
+
+ @param acl_user The object where to store the salt
+ @param password The password hash containing the salt
+ @param password_len The length of the password hash
+
+ Despite the name of the function it is used when loading ACLs from disk
+ to store the password hash in the ACL_USER object.
*/
static
void
set_user_salt(ACL_USER *acl_user, const char *password, uint password_len)
{
+ /* Using old password protocol */
if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH)
{
get_salt_from_password(acl_user->salt, password);
@@ -655,7 +905,8 @@ my_bool acl_init(bool dont_read_acl_tabl
static bool
set_user_plugin (ACL_USER *user, int password_len)
{
- switch (password_len)
+ /* using old password authentication protocol */
+ switch (password_len)
{
case 0: /* no password */
case SCRAMBLED_PASSWORD_CHAR_LENGTH:
@@ -719,9 +970,11 @@ static my_bool acl_load(THD *thd, TABLE_
(void) my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50);
while (!(read_record_info.read_record(&read_record_info)))
{
+ /* Reading record from mysql.host table */
ACL_HOST host;
- update_hostname(&host.host,get_field(&mem, table->field[0]));
- host.db= get_field(&mem, table->field[1]);
+ update_hostname(&host.host,
+ get_field(&mem, table->field[0]));
+ host.db= get_field(&mem, table->field[1]);
if (lower_case_table_names && host.db)
{
/*
@@ -757,63 +1010,29 @@ static my_bool acl_load(THD *thd, TABLE_
}
#endif
(void) push_dynamic(&acl_hosts,(uchar*) &host);
- }
+ } // END reading records from mysql.host
+
my_qsort((uchar*) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
sizeof(ACL_HOST),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
freeze_size(&acl_hosts);
+ /*
+ Prepare reading from the mysql.user table
+ */
init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0,FALSE);
table->use_all_columns();
(void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100);
- password_length= table->field[2]->field_length /
- table->field[2]->charset()->mbmaxlen;
- if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
- {
- sql_print_error("Fatal error: mysql.user table is damaged or in "
- "unsupported 3.20 format.");
- goto end;
- }
-
- DBUG_PRINT("info",("user table fields: %d, password length: %d",
- table->s->fields, password_length));
-
- mysql_mutex_lock(&LOCK_global_system_variables);
- if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
- {
- if (opt_secure_auth)
- {
- mysql_mutex_unlock(&LOCK_global_system_variables);
- sql_print_error("Fatal error: mysql.user table is in old format, "
- "but server started with --secure-auth option.");
- goto end;
- }
- mysql_user_table_is_in_short_password_format= true;
- if (global_system_variables.old_passwords)
- mysql_mutex_unlock(&LOCK_global_system_variables);
- else
- {
- global_system_variables.old_passwords= 1;
- mysql_mutex_unlock(&LOCK_global_system_variables);
- sql_print_warning("mysql.user table is not updated to new password format; "
- "Disabling new password usage until "
- "mysql_fix_privilege_tables is run");
- }
- thd->variables.old_passwords= 1;
- }
- else
- {
- mysql_user_table_is_in_short_password_format= false;
- mysql_mutex_unlock(&LOCK_global_system_variables);
- }
-
+
allow_all_hosts=0;
while (!(read_record_info.read_record(&read_record_info)))
{
+ /* Reading record from mysql.user */
ACL_USER user;
bzero(&user, sizeof(user));
- update_hostname(&user.host, get_field(&mem, table->field[0]));
- user.user= get_field(&mem, table->field[1]);
+ update_hostname(&user.host,
+ get_field(&mem, table->field[MYSQL_USER_FIELD_HOST]));
+ user.user= get_field(&mem, table->field[MYSQL_USER_FIELD_USER]);
if (check_no_resolve && hostname_requires_resolving(user.host.hostname))
{
sql_print_warning("'user' entry '%s@%s' "
@@ -823,15 +1042,26 @@ static my_bool acl_load(THD *thd, TABLE_
continue;
}
- char *password= get_field(&mem, table->field[2]);
- uint password_len= password ? strlen(password) : 0;
- user.auth_string.str= password ? password : const_cast<char*>("");
- user.auth_string.length= password_len;
- set_user_salt(&user, password, password_len);
+ /* Read legacy password */
+ {
+ char *password= get_field(&mem, table->field[MYSQL_USER_FIELD_PASSWORD]);
+ uint password_len= password ? strlen(password) : 0;
+ user.auth_string.str= password ? password : const_cast<char*>("");
+ user.auth_string.length= password_len;
+ /*
+ Transform hex to octets and adjust the format.
+ */
+ set_user_salt(&user, password, password_len);
+
+ /*
+ Set temporary plugin deduced from password length. If there are
+ enough fields in the user table the real plugin will be read later.
+ */
+ user.plugin= native_password_plugin_name;
+ if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+ user.plugin= old_password_plugin_name;
+ }
- if (set_user_plugin(&user, password_len))
- continue;
-
{
uint next_field;
user.access= get_access(table,3,&next_field) & GLOBAL_ACLS;
@@ -878,7 +1108,8 @@ static my_bool acl_load(THD *thd, TABLE_
/* Starting from 4.0.2 we have more fields */
if (table->s->fields >= 31)
{
- char *ssl_type=get_field(thd->mem_root, table->field[next_field++]);
+ char *ssl_type=
+ get_field(thd->mem_root, table->field[MYSQL_USER_FIELD_SSL_TYPE]);
if (!ssl_type)
user.ssl_type=SSL_TYPE_NONE;
else if (!strcmp(ssl_type, "ANY"))
@@ -888,15 +1119,21 @@ static my_bool acl_load(THD *thd, TABLE_
else /* !strcmp(ssl_type, "SPECIFIED") */
user.ssl_type=SSL_TYPE_SPECIFIED;
- user.ssl_cipher= get_field(&mem, table->field[next_field++]);
- user.x509_issuer= get_field(&mem, table->field[next_field++]);
- user.x509_subject= get_field(&mem, table->field[next_field++]);
+ user.ssl_cipher=
+ get_field(&mem, table->field[MYSQL_USER_FIELD_SSL_CIPHER]);
+ user.x509_issuer=
+ get_field(&mem, table->field[MYSQL_USER_FIELD_X509_ISSUER]);
+ user.x509_subject=
+ get_field(&mem, table->field[MYSQL_USER_FIELD_X509_SUBJECT]);
- char *ptr = get_field(thd->mem_root, table->field[next_field++]);
+ char *ptr= get_field(thd->mem_root,
+ table->field[MYSQL_USER_FIELD_MAX_QUESTIONS]);
user.user_resource.questions=ptr ? atoi(ptr) : 0;
- ptr = get_field(thd->mem_root, table->field[next_field++]);
+ ptr= get_field(thd->mem_root,
+ table->field[MYSQL_USER_FIELD_MAX_UPDATES]);
user.user_resource.updates=ptr ? atoi(ptr) : 0;
- ptr = get_field(thd->mem_root, table->field[next_field++]);
+ ptr= get_field(thd->mem_root,
+ table->field[MYSQL_USER_FIELD_MAX_CONNECTIONS]);
user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0;
if (user.user_resource.questions || user.user_resource.updates ||
user.user_resource.conn_per_hour)
@@ -905,24 +1142,21 @@ static my_bool acl_load(THD *thd, TABLE_
if (table->s->fields >= 36)
{
/* Starting from 5.0.3 we have max_user_connections field */
- ptr= get_field(thd->mem_root, table->field[next_field++]);
+ ptr= get_field(thd->mem_root,
+ table->field[MYSQL_USER_FIELD_MAX_USER_CONNECTIONS]);
user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
}
if (table->s->fields >= 41)
{
/* We may have plugin & auth_String fields */
- char *tmpstr= get_field(&mem, table->field[next_field++]);
+ char *tmpstr= get_field(&mem, table->field[MYSQL_USER_FIELD_PLUGIN]);
if (tmpstr)
{
- if (user.auth_string.length)
- {
- sql_print_warning("'user' entry '%s@%s' has both a password "
- "and an authentication plugin specified. The "
- "password will be ignored.",
- user.user ? user.user : "",
- user.host.hostname ? user.host.hostname : "");
- }
+ /*
+ By comparing the plugin with the built in plugins it is possible
+ to optimize the string allocation and comparision.
+ */
if (my_strcasecmp(system_charset_info, tmpstr,
native_password_plugin_name.str) == 0)
user.plugin= native_password_plugin_name;
@@ -930,18 +1164,47 @@ static my_bool acl_load(THD *thd, TABLE_
if (my_strcasecmp(system_charset_info, tmpstr,
old_password_plugin_name.str) == 0)
user.plugin= old_password_plugin_name;
- else
+ else
+ if (my_strcasecmp(system_charset_info, tmpstr,
+ sha256_password_plugin_name.str) == 0)
+ user.plugin= sha256_password_plugin_name;
+ else
{
user.plugin.str= tmpstr;
user.plugin.length= strlen(tmpstr);
}
- user.auth_string.str= get_field(&mem, table->field[next_field++]);
+ if (user.auth_string.length &&
+ user.plugin.str != sha256_password_plugin_name.str &&
+ user.plugin.str != native_password_plugin_name.str &&
+ user.plugin.str != old_password_plugin_name.str)
+ {
+ sql_print_warning("'user' entry '%s@%s' has both a password "
+ "and an authentication plugin specified. The "
+ "password will be ignored.",
+ user.user ? user.user : "",
+ user.host.hostname ? user.host.hostname : "");
+ }
+ user.auth_string.str=
+ get_field(&mem,
+ table->field[MYSQL_USER_FIELD_AUTHENTICATION_STRING]);
if (!user.auth_string.str)
user.auth_string.str= const_cast<char*>("");
user.auth_string.length= strlen(user.auth_string.str);
}
}
- }
+ if (table->s->fields >= 42)
+ {
+ /* We have a new password field */
+ char *password= get_field(&mem,
+ table->field[MYSQL_USER_FIELD_PASSWORD2]);
+ int password_len= 0;
+ if (password)
+ {
+ password_len= strlen(password)+1;
+ memcpy(user.sha2_hash, password, password_len);
+ }
+ }
+ } // end if (table->s->fields >= 31)
else
{
user.ssl_type=SSL_TYPE_NONE;
@@ -964,17 +1227,66 @@ static my_bool acl_load(THD *thd, TABLE_
(user.host.hostname[0] == wild_many && !user.host.hostname[1]))
allow_all_hosts=1; // Anyone can connect
}
- }
+ } // END while reading records from the mysql.user table
+
my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
sizeof(ACL_USER),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
freeze_size(&acl_users);
+ /* Legacy password integrity checks ----------------------------------------*/
+ {
+ password_length= table->field[MYSQL_USER_FIELD_PASSWORD]->field_length /
+ table->field[MYSQL_USER_FIELD_PASSWORD]->charset()->mbmaxlen;
+ if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+ {
+ sql_print_error("Fatal error: mysql.user table is damaged or in "
+ "unsupported 3.20 format.");
+ goto end;
+ }
+
+ DBUG_PRINT("info",("user table fields: %d, password length: %d",
+ table->s->fields, password_length));
+
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
+ {
+ if (opt_secure_auth)
+ {
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ sql_print_error("Fatal error: mysql.user table is in old format, "
+ "but server started with --secure-auth option.");
+ goto end;
+ }
+ mysql_user_table_is_in_short_password_format= true;
+ if (global_system_variables.old_passwords)
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ else
+ {
+ global_system_variables.old_passwords= 1;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ sql_print_warning("mysql.user table is not updated to new password format; "
+ "Disabling new password usage until "
+ "mysql_fix_privilege_tables is run");
+ }
+ thd->variables.old_passwords= 1;
+ }
+ else
+ {
+ mysql_user_table_is_in_short_password_format= false;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ }
+ } /* End legacy password integrity checks ----------------------------------*/
+
+ /*
+ Prepare reading from the mysql.db table
+ */
init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0,FALSE);
table->use_all_columns();
(void) my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100);
while (!(read_record_info.read_record(&read_record_info)))
{
+ /* Reading record in mysql.db */
ACL_DB db;
update_hostname(&db.host,get_field(&mem, table->field[MYSQL_DB_FIELD_HOST]));
db.db=get_field(&mem, table->field[MYSQL_DB_FIELD_DB]);
@@ -1023,12 +1335,14 @@ static my_bool acl_load(THD *thd, TABLE_
}
#endif
(void) push_dynamic(&acl_dbs,(uchar*) &db);
- }
+ } // END reading records from mysql.db tables
+
my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
sizeof(ACL_DB),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
freeze_size(&acl_dbs);
+ /* Prepare to read records from the mysql.proxies_priv table */
(void) my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER),
50, 100);
if (tables[3].table)
@@ -1038,6 +1352,7 @@ static my_bool acl_load(THD *thd, TABLE_
table->use_all_columns();
while (!(read_record_info.read_record(&read_record_info)))
{
+ /* Reading record in mysql.proxies_priv */
ACL_PROXY_USER proxy;
proxy.init(table, &mem);
if (proxy.check_validity(check_no_resolve))
@@ -1047,7 +1362,8 @@ static my_bool acl_load(THD *thd, TABLE_
end_read_record(&read_record_info);
goto end;
}
- }
+ } // END reading records from the mysql.proxies_priv table
+
my_qsort((uchar*) dynamic_element(&acl_proxy_users, 0, ACL_PROXY_USER*),
acl_proxy_users.elements,
sizeof(ACL_PROXY_USER), (qsort_cmp) acl_compare);
@@ -1405,8 +1721,8 @@ static void acl_update_user(const char *
const LEX_STRING *plugin,
const LEX_STRING *auth)
{
+ DBUG_ENTER("acl_update_user");
mysql_mutex_assert_owner(&acl_cache->lock);
-
for (uint i=0 ; i < acl_users.elements ; i++)
{
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
@@ -1417,7 +1733,7 @@ static void acl_update_user(const char *
(acl_user->host.hostname &&
!my_strcasecmp(system_charset_info, host, acl_user->host.hostname)))
{
- if (plugin->str[0])
+ if (plugin->length > 0)
{
acl_user->plugin.str= strmake_root(&mem, plugin->str, plugin->length);
acl_user->plugin.length= plugin->length;
@@ -1444,13 +1760,19 @@ static void acl_update_user(const char *
acl_user->x509_subject= (x509_subject ?
strdup_root(&mem,x509_subject) : 0);
}
- if (password)
+ if (plugin->str == sha256_password_plugin_name.str)
+ {
+ memcpy(acl_user->sha2_hash, password, password_len);
+ }
+ else
+ if (password)
set_user_salt(acl_user, password, password_len);
/* search complete: */
break;
}
}
}
+ DBUG_VOID_RETURN;
}
@@ -1465,6 +1787,7 @@ static void acl_insert_user(const char *
const LEX_STRING *plugin,
const LEX_STRING *auth)
{
+ DBUG_ENTER("acl_insert_user");
ACL_USER acl_user;
mysql_mutex_assert_owner(&acl_cache->lock);
@@ -1486,7 +1809,6 @@ static void acl_insert_user(const char *
acl_user.auth_string.str= strmake_root(&mem, password, password_len);
acl_user.auth_string.length= password_len;
}
-
acl_user.access=privileges;
acl_user.user_resource = *mqh;
acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
@@ -1497,7 +1819,16 @@ static void acl_insert_user(const char *
acl_user.x509_issuer= x509_issuer ? strdup_root(&mem,x509_issuer) : 0;
acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0;
- set_user_salt(&acl_user, password, password_len);
+ /*
+ If the plugin is sha256 based authentication then we use the sha2_hash
+ as a password store. For other plugins we fall back on the old storage.
+ */
+ if (plugin->str == sha256_password_plugin_name.str)
+ {
+ memcpy(acl_user.sha2_hash, password, password_len);
+ }
+ else
+ set_user_salt(&acl_user, password, password_len);
(void) push_dynamic(&acl_users,(uchar*) &acl_user);
if (!acl_user.host.hostname ||
@@ -1508,6 +1839,7 @@ static void acl_insert_user(const char *
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
rebuild_check_host();
+ DBUG_VOID_RETURN;
}
@@ -1759,22 +2091,19 @@ bool acl_check_host(const char *host, co
}
-/*
+/**
Check if the user is allowed to change password
- SYNOPSIS:
- check_change_password()
- thd THD
- host hostname for the user
- user user name
- new_password new password
-
- NOTE:
- new_password cannot be NULL
-
- RETURN VALUE
- 0 OK
- 1 ERROR ; In this case the error is sent to the client.
+ @param thd THD
+ @param host Hostname for the user
+ @param user User name
+ @param new_password new password
+
+ new_password cannot be NULL
+
+ @return Error status
+ @retval 0 OK
+ @retval 1 ERROR; In this case the error is sent to the client.
*/
int check_change_password(THD *thd, const char *host, const char *user,
@@ -1799,30 +2128,24 @@ int check_change_password(THD *thd, cons
MYF(0));
return(1);
}
- size_t len= strlen(new_password);
- if (len && len != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
- len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
- {
- my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
- return -1;
- }
+
return(0);
}
-/*
- Change a password for a user
-
- SYNOPSIS
- change_password()
- thd Thread handle
- host Hostname
- user User name
- new_password New password for host@user
+/**
+ Change a password hash for a user.
- RETURN VALUES
- 0 ok
- 1 ERROR; In this case the error is sent to the client.
+ @param thd Thread handle
+ @param host Hostname
+ @param user User name
+ @param new_password New password hash for host@user
+
+ @see set_var_password::update(THD *thd)
+
+ @return Error code
+ @retval 0 ok
+ @retval 1 ERROR; In this case the error is sent to the client.
*/
bool change_password(THD *thd, const char *host, const char *user,
@@ -1836,6 +2159,7 @@ bool change_password(THD *thd, const cha
bool save_binlog_row_based;
uint new_password_len= (uint) strlen(new_password);
bool result= 1;
+ enum mysql_user_table_field password_field= MYSQL_USER_FIELD_PASSWORD;
DBUG_ENTER("change_password");
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
host,user,new_password));
@@ -1883,22 +2207,56 @@ bool change_password(THD *thd, const cha
goto end;
}
+ if (acl_user->plugin.length == 0)
+ {
+ acl_user->plugin.length= default_auth_plugin_name->length;
+ acl_user->plugin.str= default_auth_plugin_name->str;
+ }
+
+ /*
+ update loaded acl entry:
+ TODO Should password depend on @@old_variables here?
+ - Probably not if the user exists and have a plugin set already.
+ */
+ if (my_strcasecmp(system_charset_info, acl_user->plugin.str,
+ sha256_password_plugin_name.str) == 0)
+ {
+ password_field= MYSQL_USER_FIELD_PASSWORD2;
+ if (new_password_len < CRYPT_MAX_PASSWORD_SIZE+1)
+ memcpy(acl_user->sha2_hash, new_password, new_password_len+1);
+ }
+ else
if (my_strcasecmp(system_charset_info, acl_user->plugin.str,
- native_password_plugin_name.str) &&
+ native_password_plugin_name.str) == 0 ||
my_strcasecmp(system_charset_info, acl_user->plugin.str,
- old_password_plugin_name.str))
+ old_password_plugin_name.str) == 0)
{
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_SET_PASSWORD_AUTH_PLUGIN, ER(ER_SET_PASSWORD_AUTH_PLUGIN));
+ acl_user->plugin= native_password_plugin_name;
+ password_field= MYSQL_USER_FIELD_PASSWORD;
+ /*
+ Update loaded acl entry in memory.
+ set_user_salt() stores a binary (compact) representation of the password
+ in memory (acl_user->salt and salt_len).
+ set_user_plugin() sets the appropriate plugin based on password length and
+ if the length doesn't match a warning is issued.
+ */
+ set_user_salt(acl_user, new_password, new_password_len);
+ set_user_plugin(acl_user, new_password_len);
+ } else
+ {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SET_PASSWORD_AUTH_PLUGIN, ER(ER_SET_PASSWORD_AUTH_PLUGIN));
+ /*
+ An undefined password factory could very well mean that the password
+ field is empty.
+ */
+ new_password_len= 0;
}
- /* update loaded acl entry: */
- set_user_salt(acl_user, new_password, new_password_len);
- set_user_plugin(acl_user, new_password_len);
-
- if (update_user_table(thd, table,
- acl_user->host.hostname ? acl_user->host.hostname : "",
- acl_user->user ? acl_user->user : "",
- new_password, new_password_len))
+
+ if (update_user_table(table,
+ acl_user->host.hostname ? acl_user->host.hostname : "",
+ acl_user->user ? acl_user->user : "",
+ new_password, new_password_len, password_field))
{
mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */
goto end;
@@ -2130,22 +2488,25 @@ bool hostname_requires_resolving(const c
}
-/*
+/**
Update record for user in mysql.user privilege table with new password.
- SYNOPSIS
- update_user_table()
- thd Thread handle
- table Pointer to TABLE object for open mysql.user table
- host/user Hostname/username pair identifying user for which
- new password should be set
- new_password New password
- new_password_len Length of new password
+ @param table Pointer to TABLE object for open mysql.user table
+ @param host Hostname
+ @param user Username
+ @param new_password New password hash
+ @param new_password_len Length of new password hash
+ @param password_field The password field to use
+
+ @see change_password
+
*/
-static bool update_user_table(THD *thd, TABLE *table,
- const char *host, const char *user,
- const char *new_password, uint new_password_len)
+static bool
+update_user_table(TABLE *table,
+ const char *host, const char *user,
+ const char *new_password, uint new_password_len,
+ enum mysql_user_table_field password_field)
{
char user_key[MAX_KEY_LENGTH];
int error;
@@ -2153,8 +2514,11 @@ static bool update_user_table(THD *thd,
DBUG_PRINT("enter",("user: %s host: %s",user,host));
table->use_all_columns();
- table->field[0]->store(host,(uint) strlen(host), system_charset_info);
- table->field[1]->store(user,(uint) strlen(user), system_charset_info);
+ DBUG_ASSERT(host != '\0');
+ table->field[MYSQL_USER_FIELD_HOST]->store(host,(uint) strlen(host),
+ system_charset_info);
+ table->field[MYSQL_USER_FIELD_USER]->store(user,(uint) strlen(user),
+ system_charset_info);
key_copy((uchar *) user_key, table->record[0], table->key_info,
table->key_info->key_length);
@@ -2167,13 +2531,17 @@ static bool update_user_table(THD *thd,
DBUG_RETURN(1); /* purecov: deadcode */
}
store_record(table,record[1]);
- table->field[2]->store(new_password, new_password_len, system_charset_info);
+
+ table->field[(int)password_field]->store(new_password, new_password_len,
+ system_charset_info);
+
if ((error=table->file->ha_update_row(table->record[1],table->record[0])) &&
- error != HA_ERR_RECORD_IS_THE_SAME)
+ error != HA_ERR_RECORD_IS_THE_SAME)
{
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
DBUG_RETURN(1);
}
+
DBUG_RETURN(0);
}
@@ -2210,12 +2578,44 @@ static bool test_if_create_new_users(THD
return create_new_users;
}
+inline bool auth_plugin_is_built_in(const char *plugin_name)
+{
+ return (plugin_name == native_password_plugin_name.str ||
+ plugin_name == sha256_password_plugin_name.str ||
+ plugin_name == old_password_plugin_name.str);
+}
+
+void optimize_plugin_compare_by_pointer(LEX_STRING *plugin_name)
+{
+ if (my_strcasecmp(system_charset_info, sha256_password_plugin_name.str,
+ plugin_name->str) == 0)
+ {
+ plugin_name->str= sha256_password_plugin_name.str;
+ plugin_name->length= sha256_password_plugin_name.length;
+ }
+ else
+ if (my_strcasecmp(system_charset_info, native_password_plugin_name.str,
+ plugin_name->str) == 0)
+ {
+ plugin_name->str= native_password_plugin_name.str;
+ plugin_name->length= native_password_plugin_name.length;
+ }
+ else
+ if (my_strcasecmp(system_charset_info, old_password_plugin_name.str,
+ plugin_name->str) == 0)
+ {
+ plugin_name->str= old_password_plugin_name.str;
+ plugin_name->length= old_password_plugin_name.length;
+ }
+
+ DBUG_ASSERT(auth_plugin_is_built_in(native_password_plugin_name.str));
+}
/****************************************************************************
Handle GRANT commands
****************************************************************************/
-static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
+static int replace_user_table(THD *thd, TABLE *table, LEX_USER *combo,
ulong rights, bool revoke_grant,
bool can_create_user, bool no_auto_create)
{
@@ -2226,27 +2626,17 @@ static int replace_user_table(THD *thd,
char what= (revoke_grant) ? 'N' : 'Y';
uchar user_key[MAX_KEY_LENGTH];
LEX *lex= thd->lex;
+ bool sha2_plugin= false;
DBUG_ENTER("replace_user_table");
mysql_mutex_assert_owner(&acl_cache->lock);
-
- if (combo.password.str && combo.password.str[0])
- {
- if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
- combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
- {
- my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
- DBUG_RETURN(-1);
- }
- password_len= combo.password.length;
- password=combo.password.str;
- }
-
+
table->use_all_columns();
- table->field[0]->store(combo.host.str,combo.host.length,
- system_charset_info);
- table->field[1]->store(combo.user.str,combo.user.length,
- system_charset_info);
+ DBUG_ASSERT(combo->host.str != '\0');
+ table->field[MYSQL_USER_FIELD_HOST]->store(combo->host.str,combo->host.length,
+ system_charset_info);
+ table->field[MYSQL_USER_FIELD_USER]->store(combo->user.str,combo->user.length,
+ system_charset_info);
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
@@ -2254,12 +2644,35 @@ static int replace_user_table(THD *thd,
HA_WHOLE_KEY,
HA_READ_KEY_EXACT))
{
- /* what == 'N' means revoke */
+ /*
+ The user record wasn't found; if the intention was to revoke privileges
+ (indicated by what == 'N') then execution must fail now.
+ */
if (what == 'N')
{
- my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
+ my_error(ER_NONEXISTING_GRANT, MYF(0), combo->user.str, combo->host.str);
goto end;
}
+
+ /* 1. Unresolved plugins become default plugin */
+ if (!combo->uses_identified_with_clause)
+ {
+ combo->plugin.str= default_auth_plugin_name->str;
+ combo->plugin.length= default_auth_plugin_name->length;
+ combo->uses_identified_with_clause= false;
+ }
+ /* 2. Digest password if needed (plugin must have been resolved) */
+ if (combo->uses_identified_by_clause)
+ {
+ if (digest_password(thd, combo))
+ {
+ // TODO issue error
+ error= 1;
+ goto end;
+ }
+ }
+ password= combo->password.str;
+ password_len= combo->password.length;
/*
There are four options which affect the process of creation of
a new user (mysqld option --safe-create-user, 'insert' privilege
@@ -2273,9 +2686,11 @@ static int replace_user_table(THD *thd,
see also test_if_create_new_users()
*/
- else if (!password_len && !combo.plugin.length && no_auto_create)
+ if (!password_len &&
+ auth_plugin_is_built_in(combo->plugin.str) &&
+ no_auto_create)
{
- my_error(ER_PASSWORD_NO_MATCH, MYF(0), combo.user.str, combo.host.str);
+ my_error(ER_PASSWORD_NO_MATCH, MYF(0), combo->user.str, combo->host.str);
goto end;
}
else if (!can_create_user)
@@ -2284,41 +2699,157 @@ static int replace_user_table(THD *thd,
thd->security_ctx->user, thd->security_ctx->host_or_ip);
goto end;
}
- else if (combo.plugin.str[0])
+ else if (combo->plugin.str[0])
{
- if (!plugin_is_ready(&combo.plugin, MYSQL_AUTHENTICATION_PLUGIN))
+ if (!plugin_is_ready(&combo->plugin, MYSQL_AUTHENTICATION_PLUGIN))
{
- my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), combo.plugin.str);
+ my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), combo->plugin.str);
goto end;
}
}
old_row_exists = 0;
restore_record(table,s->default_values);
- table->field[0]->store(combo.host.str,combo.host.length,
- system_charset_info);
- table->field[1]->store(combo.user.str,combo.user.length,
- system_charset_info);
- table->field[2]->store(password, password_len,
- system_charset_info);
+ DBUG_ASSERT(combo->host.str != '\0');
+ table->field[MYSQL_USER_FIELD_HOST]->store(combo->host.str,combo->host.length,
+ system_charset_info);
+ table->field[MYSQL_USER_FIELD_USER]->store(combo->user.str,combo->user.length,
+ system_charset_info);
+ /*
+ Examine the password hash to determine which field to use when storing it.
+ */
+ if (combo->plugin.str == sha256_password_plugin_name.str)
+ {
+ /* Use the Password2 field */
+ if (password_len > 0)
+ table->
+ field[MYSQL_USER_FIELD_PASSWORD2]->store(password, password_len+1,
+ system_charset_info);
+ /* Assert that the proper plugin is set */
+ table->
+ field[MYSQL_USER_FIELD_PLUGIN]->
+ store(sha256_password_plugin_name.str,
+ sha256_password_plugin_name.length,
+ system_charset_info);
+
+ }
+ else
+ {
+ /* Use the legacy Password field */
+ table->field[MYSQL_USER_FIELD_PASSWORD]->store(password, password_len,
+ system_charset_info);
+ table->field[MYSQL_USER_FIELD_PASSWORD2]->store("\0", 1,
+ system_charset_info);
+ }
}
- else
+ else // if (table->file->ha_index_read_idx_map [..]
{
+ /*
+ There is a matching user record ------------------------------------------
+ */
+
old_row_exists = 1;
store_record(table,record[1]); // Save copy for update
- /* what == 'N' means revoke */
- if (combo.plugin.length && what != 'N')
+
+ /* 1. resolve plugins in the LEX_USER struct if needed */
+ if (!combo->uses_identified_with_clause)
+ {
+ /*
+ Get old plugin value from storage.
+ */
+ combo->plugin.str=
+ get_field(thd->mem_root, table->field[MYSQL_USER_FIELD_PLUGIN]);
+
+ /*
+ It is important not to include the trailing '\0' in the string length
+ because otherwise the plugin hash search will fail.
+ */
+ if (combo->plugin.str)
+ {
+ combo->plugin.length= strlen(combo->plugin.str);
+
+ /*
+ Optimize for pointer comparision of built-in plugin name
+ */
+
+ optimize_plugin_compare_by_pointer(&combo->plugin);
+ }
+ }
+
+ /* No value for plugin field means default plugin is used */
+ if (combo->plugin.str == NULL || combo->plugin.str == '\0')
+ {
+ combo->plugin.str= default_auth_plugin_name->str;
+ combo->plugin.length= default_auth_plugin_name->length;
+ }
+
+ if (combo->uses_identified_with_clause)
+ {
+ /*
+ Don't allow old plugin fields to change.
+ */
+ char *old_plugin= get_field(thd->mem_root,
+ table->field[MYSQL_USER_FIELD_PLUGIN]);
+ if (old_plugin != NULL &&
+ my_strcasecmp(system_charset_info, combo->plugin.str, old_plugin))
+ {
+ error= 1;
+ my_error(ER_GRANT_PLUGIN_USER_EXISTS, MYF(0), combo->user.length,
+ combo->user.str);
+ goto end;
+ }
+ }
+
+ if (!combo->uses_authentication_string_clause)
+ {
+ combo->auth.str= get_field(thd->mem_root,
+ table->field[MYSQL_USER_FIELD_AUTHENTICATION_STRING]);
+ if (combo->auth.str)
+ combo->auth.length= strlen(combo->auth.str);
+ else
+ combo->auth.length= 0;
+ }
+
+ /* 2. Digest password if needed (plugin must have been resolved */
+ if (combo->uses_identified_by_clause)
{
- my_error(ER_GRANT_PLUGIN_USER_EXISTS, MYF(0), combo.user.length,
- combo.user.str);
+ if (digest_password(thd, combo))
+ {
+ // TODO issue error
+ error= 1;
goto end;
+ }
+ }
+ password= combo->password.str;
+ password_len= combo->password.length;
+
+ if (password_len > 0)
+ {
+ /*
+ Examine the password hash to determine which field to use when storing
+ it.
+ */
+ if (combo->plugin.str == sha256_password_plugin_name.str)
+ {
+ sha2_plugin= true;
+ table->field[MYSQL_USER_FIELD_PASSWORD2]->
+ store(password, password_len, system_charset_info);
+ }
+ else
+ {
+ /* The legacy Password field is used */
+ table->field[MYSQL_USER_FIELD_PASSWORD]->
+ store(password, password_len, system_charset_info);
+ table->field[MYSQL_USER_FIELD_PASSWORD2]->
+ store("\0", 1, system_charset_info);
+ }
}
- if (combo.password.str) // If password given
- table->field[2]->store(password, password_len, system_charset_info);
else if (!rights && !revoke_grant &&
lex->ssl_type == SSL_TYPE_NOT_SPECIFIED &&
!lex->mqh.specified_limits)
{
+
+ DBUG_PRINT("info",("Proxy user exit path"));
DBUG_RETURN(0);
}
}
@@ -2343,69 +2874,75 @@ static int replace_user_table(THD *thd,
/* We write down SSL related ACL stuff */
switch (lex->ssl_type) {
case SSL_TYPE_ANY:
- table->field[next_field]->store(STRING_WITH_LEN("ANY"),
+ table->field[MYSQL_USER_FIELD_SSL_TYPE]->store(STRING_WITH_LEN("ANY"),
&my_charset_latin1);
- table->field[next_field+1]->store("", 0, &my_charset_latin1);
- table->field[next_field+2]->store("", 0, &my_charset_latin1);
- table->field[next_field+3]->store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_SSL_CIPHER]->
+ store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_X509_ISSUER]->store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_X509_SUBJECT]->store("", 0, &my_charset_latin1);
break;
case SSL_TYPE_X509:
- table->field[next_field]->store(STRING_WITH_LEN("X509"),
+ table->field[MYSQL_USER_FIELD_SSL_TYPE]->store(STRING_WITH_LEN("X509"),
&my_charset_latin1);
- table->field[next_field+1]->store("", 0, &my_charset_latin1);
- table->field[next_field+2]->store("", 0, &my_charset_latin1);
- table->field[next_field+3]->store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_SSL_CIPHER]->
+ store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_X509_ISSUER]->store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_X509_SUBJECT]->store("", 0, &my_charset_latin1);
break;
case SSL_TYPE_SPECIFIED:
- table->field[next_field]->store(STRING_WITH_LEN("SPECIFIED"),
+ table->field[MYSQL_USER_FIELD_SSL_TYPE]->store(STRING_WITH_LEN("SPECIFIED"),
&my_charset_latin1);
- table->field[next_field+1]->store("", 0, &my_charset_latin1);
- table->field[next_field+2]->store("", 0, &my_charset_latin1);
- table->field[next_field+3]->store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_SSL_CIPHER]->store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_X509_ISSUER]->store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_X509_SUBJECT]->store("", 0, &my_charset_latin1);
if (lex->ssl_cipher)
- table->field[next_field+1]->store(lex->ssl_cipher,
+ table->field[MYSQL_USER_FIELD_SSL_CIPHER]->store(lex->ssl_cipher,
strlen(lex->ssl_cipher), system_charset_info);
if (lex->x509_issuer)
- table->field[next_field+2]->store(lex->x509_issuer,
+ table->field[MYSQL_USER_FIELD_X509_ISSUER]->store(lex->x509_issuer,
strlen(lex->x509_issuer), system_charset_info);
if (lex->x509_subject)
- table->field[next_field+3]->store(lex->x509_subject,
+ table->field[MYSQL_USER_FIELD_X509_SUBJECT]->store(lex->x509_subject,
strlen(lex->x509_subject), system_charset_info);
break;
case SSL_TYPE_NOT_SPECIFIED:
break;
case SSL_TYPE_NONE:
- table->field[next_field]->store("", 0, &my_charset_latin1);
- table->field[next_field+1]->store("", 0, &my_charset_latin1);
- table->field[next_field+2]->store("", 0, &my_charset_latin1);
- table->field[next_field+3]->store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_SSL_TYPE]->store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_SSL_CIPHER]->store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_X509_ISSUER]->store("", 0, &my_charset_latin1);
+ table->field[MYSQL_USER_FIELD_X509_SUBJECT]->store("", 0, &my_charset_latin1);
break;
}
next_field+=4;
USER_RESOURCES mqh= lex->mqh;
if (mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
- table->field[next_field]->store((longlong) mqh.questions, TRUE);
+ table->field[MYSQL_USER_FIELD_MAX_QUESTIONS]->
+ store((longlong) mqh.questions, TRUE);
if (mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
- table->field[next_field+1]->store((longlong) mqh.updates, TRUE);
+ table->field[MYSQL_USER_FIELD_MAX_UPDATES]->
+ store((longlong) mqh.updates, TRUE);
if (mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
- table->field[next_field+2]->store((longlong) mqh.conn_per_hour, TRUE);
+ table->field[MYSQL_USER_FIELD_MAX_CONNECTIONS]->
+ store((longlong) mqh.conn_per_hour, TRUE);
if (table->s->fields >= 36 &&
(mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS))
- table->field[next_field+3]->store((longlong) mqh.user_conn, TRUE);
+ table->field[MYSQL_USER_FIELD_MAX_USER_CONNECTIONS]->
+ store((longlong) mqh.user_conn, TRUE);
mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour;
next_field+= 4;
- if (combo.plugin.str[0])
+ if (combo->plugin.length > 0 && !old_row_exists)
{
- if (table->s->fields >= 41 && combo.plugin.str[0])
+ if (table->s->fields >= 41)
{
- table->field[next_field]->store(combo.plugin.str, combo.plugin.length,
- system_charset_info);
- table->field[next_field]->set_notnull();
- table->field[next_field + 1]->store(combo.auth.str, combo.auth.length,
- system_charset_info);
- table->field[next_field + 1]->set_notnull();
+ table->field[MYSQL_USER_FIELD_PLUGIN]->
+ store(combo->plugin.str, combo->plugin.length, system_charset_info);
+ table->field[MYSQL_USER_FIELD_PLUGIN]->set_notnull();
+ table->field[MYSQL_USER_FIELD_AUTHENTICATION_STRING]->
+ store(combo->auth.str, combo->auth.length, system_charset_info);
+ table->field[MYSQL_USER_FIELD_AUTHENTICATION_STRING]->set_notnull();
}
else
{
@@ -2416,7 +2953,7 @@ static int replace_user_table(THD *thd,
}
if (old_row_exists)
- {
+ {
/*
We should NEVER delete from the user table, as a uses can still
use mysqld even if he doesn't have any privileges in the user table!
@@ -2451,26 +2988,26 @@ end:
{
acl_cache->clear(1); // Clear privilege cache
if (old_row_exists)
- acl_update_user(combo.user.str, combo.host.str,
- combo.password.str, password_len,
+ acl_update_user(combo->user.str, combo->host.str,
+ combo->password.str, password_len,
lex->ssl_type,
lex->ssl_cipher,
lex->x509_issuer,
lex->x509_subject,
&lex->mqh,
rights,
- &combo.plugin,
- &combo.auth);
+ &combo->plugin,
+ &combo->auth);
else
- acl_insert_user(combo.user.str, combo.host.str, password, password_len,
+ acl_insert_user(combo->user.str, combo->host.str, password, password_len,
lex->ssl_type,
lex->ssl_cipher,
lex->x509_issuer,
lex->x509_subject,
&lex->mqh,
rights,
- &combo.plugin,
- &combo.auth);
+ &combo->plugin,
+ &combo->auth);
}
DBUG_RETURN(error);
}
@@ -3667,9 +4204,18 @@ int mysql_table_grant(THD *thd, TABLE_LI
{
result= TRUE;
continue;
- }
+ }
+
+ /*
+ No User, but a password?
+ They did GRANT ... TO CURRENT_USER() IDENTIFIED BY ... !
+ Get the current user, and shallow-copy the new password to them!
+ */
+ if (!tmp_Str->user.str && tmp_Str->password.str)
+ Str->password= tmp_Str->password;
+
/* Create user if needed */
- error=replace_user_table(thd, tables[0].table, *Str,
+ error=replace_user_table(thd, tables[0].table, Str,
0, revoke_grant, create_new_users,
test(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER));
@@ -3900,8 +4446,9 @@ bool mysql_routine_grant(THD *thd, TABLE
result= TRUE;
continue;
}
+
/* Create user if needed */
- error=replace_user_table(thd, tables[0].table, *Str,
+ error=replace_user_table(thd, tables[0].table, Str,
0, revoke_grant, create_new_users,
test(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER));
@@ -3971,6 +4518,79 @@ bool mysql_routine_grant(THD *thd, TABLE
}
+/**
+ Allocates a new buffer and calculates digested password hash based on plugin
+ and old_passwords. The old buffer containing the clear text password is
+ simply discarded as this memory belongs to the LEX will be freed when the
+ session ends.
+
+ @param THD the tread handler used for allocating memory
+ @param user_record[in, out] The user record
+
+ @return Failure state
+ @retval 0 OK
+ @retval 1 ERROR
+*/
+
+int digest_password(THD *thd, LEX_USER *user_record)
+{
+ /*
+ Transform password into a password hash
+ */
+ if (user_record->plugin.str == sha256_password_plugin_name.str)
+ {
+ char *buff= (char *) thd->alloc(CRYPT_MAX_PASSWORD_SIZE+1);
+ if (buff == NULL)
+ {
+ //TODO issue OOM error
+ return 1;
+ }
+ my_make_scrambled_password(buff, user_record->password.str,
+ user_record->password.length);
+ user_record->password.str= buff;
+ user_record->password.length= strlen(buff)+1;
+ }
+ else
+ if (user_record->plugin.str == native_password_plugin_name.str ||
+ user_record->plugin.str == old_password_plugin_name.str)
+ {
+ if (thd->variables.old_passwords == 1)
+ {
+ char *buff=
+ (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
+ if (buff == NULL)
+ {
+ // TODO issue OOM error
+ return 1;
+ }
+ my_make_scrambled_password_323(buff, user_record->password.str,
+ user_record->password.length);
+ user_record->password.str= buff;
+ user_record->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ }
+ else
+ {
+ char *buff=
+ (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
+ if (buff == NULL)
+ {
+ // TODO issue OOM error
+ return 1;
+ }
+ my_make_scrambled_password_sha1(buff, user_record->password.str,
+ user_record->password.length);
+ user_record->password.str= buff;
+ user_record->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
+ }
+ } // end if native_password_plugin_name || old_password_plugin_name
+ else
+ {
+ user_record->password.str= 0;
+ user_record->password.length= 0;
+ }
+ return 0;
+}
+
bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
ulong rights, bool revoke_grant, bool is_proxy)
{
@@ -4081,7 +4701,8 @@ bool mysql_grant(THD *thd, const char *d
*/
if (!tmp_Str->user.str && tmp_Str->password.str)
Str->password= tmp_Str->password;
- if (replace_user_table(thd, tables[0].table, *Str,
+
+ if (replace_user_table(thd, tables[0].table, Str,
(!db ? rights : 0), revoke_grant, create_new_users,
test(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER)))
@@ -5275,6 +5896,14 @@ bool mysql_show_grants(THD *thd,LEX_USER
global.append(lex_user->host.str,lex_user->host.length,
system_charset_info);
global.append ('\'');
+ if (acl_user->plugin.str == sha256_password_plugin_name.str)
+ {
+ global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '"));
+ //global.append((const char *)&acl_user->sha2_hash[0]);
+ global.append("{$5}");
+ global.append('\'');
+ }
+ else
if (acl_user->salt_len)
{
char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
@@ -6492,12 +7121,27 @@ bool mysql_create_user(THD *thd, List <L
log_query.append(STRING_WITH_LEN("CREATE USER"));
while ((tmp_user_name= user_list++))
{
+ /*
+ If tmp_user_name.user.str is == NULL then
+ user_name := tmp_user_name.
+ Else user_name.user := sctx->user
+ TODO and all else is turned to NULL !! Why?
+ */
if (!(user_name= get_current_user(thd, tmp_user_name)))
{
result= TRUE;
continue;
}
+ /*
+ If no plugin is given, set a default plugin (sha256_password_plugin)
+ */
+ if (user_name->plugin.length == 0 && user_name->uses_identified_with_clause)
+ {
+ user_name->plugin.str= default_auth_plugin_name->str;
+ user_name->plugin.length= default_auth_plugin_name->length;
+ }
+
log_query.append(' ');
append_user(&log_query, user_name, FALSE, TRUE);
log_query.append(',');
@@ -6513,7 +7157,7 @@ bool mysql_create_user(THD *thd, List <L
continue;
}
- if (replace_user_table(thd, tables[0].table, *user_name, 0, 0, 1, 0))
+ if (replace_user_table(thd, tables[0].table, user_name, 0, 0, 1, 0))
{
append_user(&wrong_users, user_name, wrong_users.length() > 0);
result= TRUE;
@@ -6521,7 +7165,7 @@ bool mysql_create_user(THD *thd, List <L
}
some_users_created= TRUE;
- }
+ } // END while tmp_user_name= user_lists++
mysql_mutex_unlock(&acl_cache->lock);
@@ -6783,7 +7427,7 @@ bool mysql_revoke_all(THD *thd, List <L
}
if (replace_user_table(thd, tables[0].table,
- *lex_user, ~(ulong)0, 1, 0, 0))
+ lex_user, ~(ulong)0, 1, 0, 0))
{
result= -1;
continue;
@@ -7100,7 +7744,6 @@ bool sp_grant_privileges(THD *thd, const
List<LEX_USER> user_list;
bool result;
ACL_USER *au;
- char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
Dummy_error_handler error_handler;
DBUG_ENTER("sp_grant_privileges");
@@ -7140,37 +7783,10 @@ bool sp_grant_privileges(THD *thd, const
combo->password= empty_lex_str;
combo->plugin= empty_lex_str;
combo->auth= empty_lex_str;
-
- if(au)
- {
- if (au->salt_len)
- {
- if (au->salt_len == SCRAMBLE_LENGTH)
- {
- make_password_from_salt(passwd_buff, au->salt);
- combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
- }
- else if (au->salt_len == SCRAMBLE_LENGTH_323)
- {
- make_password_from_salt_323(passwd_buff, (ulong *) au->salt);
- combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
- }
- else
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_PASSWD_LENGTH,
- ER(ER_PASSWD_LENGTH), SCRAMBLED_PASSWORD_CHAR_LENGTH);
- return TRUE;
- }
- combo->password.str= passwd_buff;
- }
-
- if (au->plugin.str != native_password_plugin_name.str &&
- au->plugin.str != old_password_plugin_name.str)
- {
- combo->plugin= au->plugin;
- combo->auth= au->auth_string;
- }
- }
+ combo->uses_identified_by_clause= false;
+ combo->uses_identified_with_clause= false;
+ combo->uses_identified_by_password_clause= false;
+ combo->uses_authentication_string_clause= false;
if (user_list.push_back(combo))
DBUG_RETURN(TRUE);
@@ -8284,9 +8900,14 @@ static bool find_mpvio_user(MPVIO_EXT *m
compare_hostname(&acl_user_tmp->host, mpvio->host, mpvio->ip))
{
mpvio->acl_user= acl_user_tmp->copy(mpvio->mem_root);
- if (acl_user_tmp->plugin.str == native_password_plugin_name.str ||
- acl_user_tmp->plugin.str == old_password_plugin_name.str)
- mpvio->acl_user_plugin= acl_user_tmp->plugin;
+
+ /*
+ When setting mpvio->acl_user_plugin we can save memory allocation if
+ this is a built in plugin.
+ */
+ optimize_plugin_compare_by_pointer(&acl_user_tmp->plugin);
+ if (auth_plugin_is_built_in(acl_user_tmp->plugin.str))
+ mpvio->acl_user_plugin= mpvio->acl_user->plugin;
else
make_lex_string_root(mpvio->mem_root,
&mpvio->acl_user_plugin,
@@ -8303,11 +8924,11 @@ static bool find_mpvio_user(MPVIO_EXT *m
DBUG_RETURN (1);
}
- /* user account requires non-default plugin and the client is too old */
if (mpvio->acl_user->plugin.str != native_password_plugin_name.str &&
mpvio->acl_user->plugin.str != old_password_plugin_name.str &&
!(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH))
{
+ /* user account requires non-default plugin and the client is too old */
DBUG_ASSERT(my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
native_password_plugin_name.str));
DBUG_ASSERT(my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
@@ -8323,7 +8944,7 @@ static bool find_mpvio_user(MPVIO_EXT *m
strmake(mpvio->auth_info.authenticated_as, mpvio->acl_user->user ?
mpvio->acl_user->user : "", USERNAME_LENGTH);
DBUG_PRINT("info", ("exit: user=%s, auth_string=%s, authenticated as=%s"
- "plugin=%s",
+ ", plugin=%s",
mpvio->auth_info.user_name,
mpvio->auth_info.auth_string,
mpvio->auth_info.authenticated_as,
@@ -9094,22 +9715,27 @@ static bool acl_check_ssl(THD *thd, cons
static int do_auth_once(THD *thd, const LEX_STRING *auth_plugin_name,
MPVIO_EXT *mpvio)
{
+ DBUG_ENTER("do_auth_once");
int res= CR_OK, old_status= MPVIO_EXT::FAILURE;
bool unlock_plugin= false;
- plugin_ref plugin;
+ plugin_ref plugin= NULL;
if (auth_plugin_name->str == native_password_plugin_name.str)
plugin= native_password_plugin;
- else
#ifndef EMBEDDED_LIBRARY
+ else
if (auth_plugin_name->str == old_password_plugin_name.str)
plugin= old_password_plugin;
- else if ((plugin= my_plugin_lock_by_name(thd, auth_plugin_name,
- MYSQL_AUTHENTICATION_PLUGIN)))
- unlock_plugin= true;
else
+ {
+ if (auth_plugin_name->length == 0)
+ auth_plugin_name= default_auth_plugin_name;
+ if ((plugin= my_plugin_lock_by_name(thd, auth_plugin_name,
+ MYSQL_AUTHENTICATION_PLUGIN)))
+ unlock_plugin= true;
+ }
#endif
- plugin= NULL;
+
mpvio->plugin= plugin;
old_status= mpvio->status;
@@ -9140,7 +9766,7 @@ static int do_auth_once(THD *thd, const
if (old_status == MPVIO_EXT::RESTART && mpvio->status == MPVIO_EXT::RESTART)
mpvio->status= MPVIO_EXT::FAILURE; // reset to the default
- return res;
+ DBUG_RETURN(res);
}
@@ -9349,6 +9975,8 @@ acl_authenticate(THD *thd, uint connect_
DBUG_RETURN(1);
}
acl_user= acl_proxy_user->copy(thd->mem_root);
+ DBUG_PRINT("info",("User %s is a PROXY and will assume a PROXIED"
+ " identity %s", auth_user,acl_user->user));
mysql_mutex_unlock(&acl_cache->lock);
}
#endif
@@ -9621,6 +10249,124 @@ static int old_password_authenticate(MYS
return CR_ERROR;
}
+static int sha256_password_authenticate(MYSQL_PLUGIN_VIO *vio,
+ MYSQL_SERVER_AUTH_INFO *info)
+{
+ uchar *pkt;
+ int pkt_len;
+ MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
+ char *user_salt_begin;
+ char *user_salt_end;
+ uint user_salt_length= 0;
+ char user_salt[CRYPT_SALT_LENGTH+1];
+ char stage2[CRYPT_MAX_PASSWORD_SIZE+1];
+ bool has_error= false;
+ const char *one_round_param[2]= {"rounds=1", 0};
+
+ DBUG_ENTER("sha256_password_authenticate");
+
+ /* generate the scramble. */
+ generate_user_salt(mpvio->scramble, SCRAMBLE_LENGTH);
+ mpvio->scramble[SCRAMBLE_LENGTH]= '\0';
+
+ /* send it to the client */
+ if (mpvio->write_packet(mpvio, (uchar*) mpvio->scramble, SCRAMBLE_LENGTH + 1))
+ DBUG_RETURN(CR_ERROR);
+
+ /*
+ To complete the handshake the authentication API demands that read_packet()
+ is called. After the call to read_packet() the user name will appear in
+ mpvio->acl_user.
+
+ Get request for user salt (1 byte). This is used to find out if user
+ supplied a password.
+ */
+ if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
+ DBUG_RETURN(CR_ERROR);
+
+ if(pkt_len == 1 && pkt[0] == 1)
+ info->password_used= PASSWORD_USED_YES;
+ else
+ info->password_used= PASSWORD_USED_NO;
+
+ /*
+ Client might have reported wrong plugin so we might need to restart the
+ handshake with a new plugin.
+ NOTE this check must happen after mpvio->read_packet()
+ */
+ if (mpvio->status == MPVIO_EXT::RESTART || has_error)
+ DBUG_RETURN(CR_ERROR);
+
+ if (mpvio->acl_user->sha2_hash[0] == 0) /* no password */
+ {
+ if (info->password_used == PASSWORD_USED_NO)
+ {
+ DBUG_PRINT("info",("Client didn't use a password. Authentication plugin "
+ " short cut path."));
+ DBUG_RETURN(CR_OK); /* Authentication can still fail because of host */
+ }
+ }
+
+ if (mpvio->acl_user && mpvio->acl_user->sha2_hash)
+ {
+ user_salt_begin= (char *)mpvio->acl_user->sha2_hash;
+ if (extract_user_salt(&user_salt_begin,
+ &user_salt_end) == CRYPT_SALT_LENGTH)
+ {
+ memcpy(user_salt, user_salt_begin, CRYPT_SALT_LENGTH);
+ user_salt_length= CRYPT_SALT_LENGTH;
+ }
+ }
+ else
+ {
+ has_error= true;
+ /*
+ Generate fake random salt; TODO should be a hash of the client
+ supplied user name and a random salt generated at server boot time.
+ */
+ create_random_string(user_salt, CRYPT_SALT_LENGTH, mpvio->rand);
+ user_salt_length= strlen(user_salt); // null terminated?
+ }
+
+ /* send user salt to the client */
+ if (mpvio->write_packet(mpvio, (uchar*) user_salt, strlen(user_salt)))
+ DBUG_RETURN(CR_ERROR);
+
+
+ /* read the reply with the encrypted password */
+ if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
+ DBUG_RETURN(CR_ERROR);
+
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+ DBUG_RETURN(CR_OK);
+#endif
+
+ if (mpvio->acl_user && user_salt_length == 0)
+ {
+ DBUG_PRINT("info",("Server plugin SHA256 has error's; exiting"));
+ DBUG_RETURN(CR_ERROR);
+ }
+
+ if (pkt_len > CRYPT_MAX_PASSWORD_SIZE+1)
+ DBUG_RETURN(CR_ERROR);
+
+ crypt_genhash_impl(stage2,
+ CRYPT_MAX_PASSWORD_SIZE,
+ (const char *)mpvio->acl_user->sha2_hash,
+ strlen((const char*)mpvio->acl_user->sha2_hash),
+ (const char *)mpvio->scramble,
+ one_round_param);
+
+ int result= memcmp(stage2,
+ pkt,
+ pkt_len);
+
+ if (result == 0 && !has_error)
+ DBUG_RETURN(CR_OK);
+ else
+ DBUG_RETURN(CR_ERROR);
+}
+
static struct st_mysql_auth native_password_handler=
{
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
@@ -9635,6 +10381,13 @@ static struct st_mysql_auth old_password
old_password_authenticate
};
+static struct st_mysql_auth sha256_password_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ sha256_password_plugin_name.str,
+ sha256_password_authenticate
+};
+
mysql_declare_plugin(mysql_password)
{
MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
@@ -9663,6 +10416,20 @@ mysql_declare_plugin(mysql_password)
NULL, /* status variables */
NULL, /* system variables */
NULL /* config options */
+},
+{
+ MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
+ &sha256_password_handler, /* type descriptor */
+ sha256_password_plugin_name.str, /* Name */
+ "Oracle", /* Author */
+ "SHA256 password authentication", /* Description */
+ PLUGIN_LICENSE_GPL, /* License */
+ NULL, /* Init function */
+ NULL, /* Deinit function */
+ 0x0100, /* Version (1.0) */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ NULL /* config options */
}
mysql_declare_plugin_end;
=== modified file 'sql/sql_acl.h'
--- a/sql/sql_acl.h 2010-10-21 09:49:16 +0000
+++ b/sql/sql_acl.h 2011-05-27 14:40:44 +0000
@@ -170,6 +170,54 @@ enum mysql_db_table_field
MYSQL_DB_FIELD_COUNT
};
+enum mysql_user_table_field
+{
+ MYSQL_USER_FIELD_HOST= 0,
+ MYSQL_USER_FIELD_USER,
+ MYSQL_USER_FIELD_PASSWORD,
+ MYSQL_USER_FIELD_SELECT_PRIV,
+ MYSQL_USER_FIELD_INSERT_PRIV,
+ MYSQL_USER_FIELD_UPDATE_PRIV,
+ MYSQL_USER_FIELD_DELETE_PRIV,
+ MYSQL_USER_FIELD_CREATE_PRIV,
+ MYSQL_USER_FIELD_DROP_PRIV,
+ MYSQL_USER_FIELD_RELOAD_PRIV,
+ MYSQL_USER_FIELD_SHUTDOWN_PRIV,
+ MYSQL_USER_FIELD_PROCESS_PRIV,
+ MYSQL_USER_FIELD_FILE_PRIV,
+ MYSQL_USER_FIELD_GRANT_PRIV,
+ MYSQL_USER_FIELD_REFERENCES_PRIV,
+ MYSQL_USER_FIELD_INDEX_PRIV,
+ MYSQL_USER_FIELD_ALTER_PRIV,
+ MYSQL_USER_FIELD_SHOW_DB_PRIV,
+ MYSQL_USER_FIELD_SUPER_PRIV,
+ MYSQL_USER_FIELD_CREATE_TMP_TABLE_PRIV,
+ MYSQL_USER_FIELD_LOCK_TABLES_PRIV,
+ MYSQL_USER_FIELD_EXECUTE_PRIV,
+ MYSQL_USER_FIELD_REPL_SLAVE_PRIV,
+ MYSQL_USER_FIELD_REPL_CLIENT_PRIV,
+ MYSQL_USER_FIELD_CREATE_VIEW_PRIV,
+ MYSQL_USER_FIELD_SHOW_VIEW_PRIV,
+ MYSQL_USER_FIELD_CREATE_ROUTINE_PRIV,
+ MYSQL_USER_FIELD_ALTER_ROUTINE_PRIV,
+ MYSQL_USER_FIELD_CREATE_USER_PRIV,
+ MYSQL_USER_FIELD_EVENT_PRIV,
+ MYSQL_USER_FIELD_TRIGGER_PRIV,
+ MYSQL_USER_FIELD_CREATE_TABLESPACE_PRIV,
+ MYSQL_USER_FIELD_SSL_TYPE,
+ MYSQL_USER_FIELD_SSL_CIPHER,
+ MYSQL_USER_FIELD_X509_ISSUER,
+ MYSQL_USER_FIELD_X509_SUBJECT,
+ MYSQL_USER_FIELD_MAX_QUESTIONS,
+ MYSQL_USER_FIELD_MAX_UPDATES,
+ MYSQL_USER_FIELD_MAX_CONNECTIONS,
+ MYSQL_USER_FIELD_MAX_USER_CONNECTIONS,
+ MYSQL_USER_FIELD_PLUGIN,
+ MYSQL_USER_FIELD_AUTHENTICATION_STRING,
+ MYSQL_USER_FIELD_PASSWORD2,
+ MYSQL_USER_FIELD_COUNT
+};
+
extern const TABLE_FIELD_DEF mysql_db_table_def;
extern bool mysql_user_table_is_in_short_password_format;
@@ -237,6 +285,7 @@ int fill_schema_schema_privileges(THD *t
int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, Item *cond);
int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, Item *cond);
int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
+int digest_password(THD *thd, LEX_USER *user_record);
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define check_grant(A,B,C,D,E,F) 0
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h 2011-04-04 10:06:13 +0000
+++ b/sql/sql_class.h 2011-05-27 14:40:44 +0000
@@ -486,7 +486,7 @@ typedef struct system_variables
my_bool keep_files_on_create;
my_bool old_alter_table;
- my_bool old_passwords;
+ uint old_passwords;
my_bool big_tables;
plugin_ref table_plugin;
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2011-04-07 12:04:22 +0000
+++ b/sql/sql_parse.cc 2011-05-27 14:40:44 +0000
@@ -7069,6 +7069,10 @@ void get_default_definer(THD *thd, LEX_U
definer->password= null_lex_str;
definer->plugin= empty_lex_str;
definer->auth= empty_lex_str;
+ definer->uses_identified_with_clause= false;
+ definer->uses_identified_by_clause= false;
+ definer->uses_authentication_string_clause= false;
+ definer->uses_identified_by_password_clause= false;
}
@@ -7122,7 +7126,10 @@ LEX_USER *create_definer(THD *thd, LEX_S
definer->host= *host_name;
definer->password.str= NULL;
definer->password.length= 0;
-
+ definer->uses_authentication_string_clause= false;
+ definer->uses_identified_by_clause= false;
+ definer->uses_identified_by_password_clause= false;
+ definer->uses_identified_with_clause= false;
return definer;
}
@@ -7142,7 +7149,31 @@ LEX_USER *create_definer(THD *thd, LEX_S
LEX_USER *get_current_user(THD *thd, LEX_USER *user)
{
if (!user->user.str) // current_user
- return create_default_definer(thd);
+ {
+ LEX_USER *default_definer= create_default_definer(thd);
+ if (default_definer)
+ {
+ /*
+ Inherit parser semantics from the statement in which the user parameter
+ was used.
+ This is needed because a st_lex_user is both used as a component in an
+ AST and as a specifier for a particular user in the ACL subsystem.
+ */
+ default_definer->uses_authentication_string_clause=
+ user->uses_authentication_string_clause;
+ default_definer->uses_identified_by_clause=
+ user->uses_identified_by_clause;
+ default_definer->uses_identified_by_password_clause=
+ user->uses_identified_by_password_clause;
+ default_definer->uses_identified_with_clause=
+ user->uses_identified_with_clause;
+ default_definer->plugin.str= user->plugin.str;
+ default_definer->plugin.length= user->plugin.length;
+ default_definer->auth.str= user->auth.str;
+ default_definer->auth.length= user->auth.length;
+ return default_definer;
+ }
+ }
return user;
}
=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy 2011-03-09 20:54:55 +0000
+++ b/sql/sql_yacc.yy 2011-05-27 14:40:44 +0000
@@ -8574,7 +8574,7 @@ function_call_conflict:
{
THD *thd= YYTHD;
Item* i1;
- if (thd->variables.old_passwords)
+ if (thd->variables.old_passwords == 1)
i1= new (thd->mem_root) Item_func_old_password($3);
else
i1= new (thd->mem_root) Item_func_password($3);
@@ -12465,12 +12465,16 @@ user:
THD *thd= YYTHD;
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
MYSQL_YYABORT;
- $$->user = $1;
+ $$->user= $1;
$$->host.str= (char *) "%";
$$->host.length= 1;
$$->password= null_lex_str;
$$->plugin= empty_lex_str;
$$->auth= empty_lex_str;
+ $$->uses_identified_by_clause= false;
+ $$->uses_identified_with_clause= false;
+ $$->uses_identified_by_password_clause= false;
+ $$->uses_authentication_string_clause= false;
if (check_string_char_length(&$$->user, ER(ER_USERNAME),
USERNAME_CHAR_LENGTH,
@@ -12482,10 +12486,15 @@ user:
THD *thd= YYTHD;
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
MYSQL_YYABORT;
- $$->user = $1; $$->host=$3;
+ $$->user= $1;
+ $$->host= $3;
$$->password= null_lex_str;
$$->plugin= empty_lex_str;
$$->auth= empty_lex_str;
+ $$->uses_identified_by_clause= false;
+ $$->uses_identified_with_clause= false;
+ $$->uses_identified_by_password_clause= false;
+ $$->uses_authentication_string_clause= false;
if (check_string_char_length(&$$->user, ER(ER_USERNAME),
USERNAME_CHAR_LENGTH,
@@ -13263,17 +13272,25 @@ text_or_password:
TEXT_STRING { $$=$1.str;}
| PASSWORD '(' TEXT_STRING ')'
{
- $$= $3.length ? YYTHD->variables.old_passwords ?
- Item_func_old_password::alloc(YYTHD, $3.str, $3.length) :
- Item_func_password::alloc(YYTHD, $3.str, $3.length) :
- $3.str;
+ if ($3.length == 0)
+ $$= $3.str;
+ else
+ switch (YYTHD->variables.old_passwords) {
+ case 1: $$= Item_func_old_password::
+ alloc(YYTHD, $3.str, $3.length);
+ break;
+ case 0:
+ case 2: $$= Item_func_password::
+ create_password_hash_buffer(YYTHD, $3.str, $3.length);
+ break;
+ }
if ($$ == NULL)
MYSQL_YYABORT;
}
| OLD_PASSWORD '(' TEXT_STRING ')'
{
- $$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str,
- $3.length) :
+ $$= $3.length ? Item_func_old_password::
+ alloc(YYTHD, $3.str, $3.length) :
$3.str;
if ($$ == NULL)
MYSQL_YYABORT;
@@ -13752,29 +13769,11 @@ grant_user:
$$=$1; $1->password=$4;
if (Lex->sql_command == SQLCOM_REVOKE)
MYSQL_YYABORT;
- if ($4.length)
- {
- if (YYTHD->variables.old_passwords)
- {
- char *buff=
- (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
- if (buff == NULL)
- MYSQL_YYABORT;
- my_make_scrambled_password_323(buff, $4.str, $4.length);
- $1->password.str= buff;
- $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
- }
- else
- {
- char *buff=
- (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
- if (buff == NULL)
- MYSQL_YYABORT;
- my_make_scrambled_password(buff, $4.str, $4.length);
- $1->password.str= buff;
- $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
- }
- }
+ /*
+ 1. Plugin must be resolved
+ 2. Password must be digested
+ */
+ $1->uses_identified_by_clause= true;
}
| user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
{
@@ -13782,6 +13781,10 @@ grant_user:
MYSQL_YYABORT;
$$= $1;
$1->password= $5;
+ /*
+ 1. Plugin must be resolved
+ */
+ $1->uses_identified_by_password_clause= true;
}
| user IDENTIFIED_SYM WITH ident_or_text
{
@@ -13789,7 +13792,7 @@ grant_user:
MYSQL_YYABORT;
$$= $1;
$1->plugin= $4;
- $1->auth= empty_lex_str;
+ $1->uses_identified_with_clause= true;
}
| user IDENTIFIED_SYM WITH ident_or_text AS TEXT_STRING_sys
{
@@ -13798,9 +13801,14 @@ grant_user:
$$= $1;
$1->plugin= $4;
$1->auth= $6;
+ $1->uses_identified_with_clause= true;
+ $1->uses_authentication_string_clause= true;
}
| user
- { $$= $1; $1->password= null_lex_str; }
+ {
+ $$= $1;
+ $1->password= null_lex_str;
+ }
;
opt_column_list:
=== modified file 'sql/structs.h'
--- a/sql/structs.h 2010-10-21 09:49:16 +0000
+++ b/sql/structs.h 2011-05-27 14:40:44 +0000
@@ -157,6 +157,10 @@ typedef int *(*update_var)(THD *, struct
typedef struct st_lex_user {
LEX_STRING user, host, password, plugin, auth;
+ bool uses_identified_by_clause;
+ bool uses_identified_with_clause;
+ bool uses_authentication_string_clause;
+ bool uses_identified_by_password_clause;
} LEX_USER;
/*
=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc 2011-04-04 10:06:13 +0000
+++ b/sql/sys_vars.cc 2011-05-27 14:40:44 +0000
@@ -10,7 +10,7 @@
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
+ along with this program; if noldot, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/*
@@ -1586,15 +1586,12 @@ static Sys_var_mybool Sys_old_alter_tabl
"old_alter_table", "Use old, non-optimized alter table",
SESSION_VAR(old_alter_table), CMD_LINE(OPT_ARG), DEFAULT(FALSE));
-static bool check_old_passwords(sys_var *self, THD *thd, set_var *var)
-{
- return mysql_user_table_is_in_short_password_format;
-}
-static Sys_var_mybool Sys_old_passwords(
+static Sys_var_uint Sys_old_passwords(
"old_passwords",
- "Use old password encryption method (needed for 4.0 and older clients)",
- SESSION_VAR(old_passwords), CMD_LINE(OPT_ARG), DEFAULT(FALSE),
- NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_old_passwords));
+ "Determine which hash algorithm to use when generating passwords using "
+ "the PASSWORD() function",
+ SESSION_VAR(old_passwords), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(0, 2), DEFAULT(0), BLOCK_SIZE(1));
static Sys_var_ulong Sys_open_files_limit(
"open_files_limit",
Attachment: [text/bzr-bundle] bzr/kristofer.pettersson@oracle.com-20110527144044-ritnjipvidfy1j2l.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk-wl5602 branch (kristofer.pettersson:3311) | Kristofer Pettersson | 27 May |