Commit 5b15cc61 authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-11340 Allow multiple alternative authentication methods for the same user

introduce the syntax

... IDENTIFIED { WITH | VIA }
      plugin [ { USING | AS } auth ]
 [ OR plugin [ { USING | AS } auth ]
 [ OR ... ]]

Server will try auth plugins in the specified order until the first
success. No protocol changes, server uses the existing "switch plugin"
packet.

The auth chain is stored in json as

  "auth_or":[{"plugin":"xxx","authentication_string":"yyy"},
             {},
             {"plugin":"foo","authentication_string":"bar"},
            ...],
  "plugin":"aaa", "authentication_string":"bbb"

Note:
* "auth_or" implies that there might be "auth_and" someday;
* one entry in the array is an empty object, meaning to take plugin/auth
  from the main json object. This preserves compatibility with
  the existing mysql.global_priv table and with the mysql.user view.
  This entry is preferrably a mysql_native_password plugin for a
  non-empty mysql.user.password column.

SET PASSWORD is supported and changes the password for the *first*
plugin in the chain that has a notion of a "password"
parent 798d1a9d
Subproject commit a4effc462ddb80b61ebb559d48b50fa8d6c0ed64
Subproject commit 1e4b08bd2989c664f6f43e0dbb2c71be9552bc8c
......@@ -65,7 +65,7 @@ alter user foo identified with 'somecoolplugin';
ERROR HY000: Operation ALTER USER failed for 'foo'@'%'
show warnings;
Level Code Message
Warning 1524 Plugin 'somecoolplugin' is not loaded
Error 1524 Plugin 'somecoolplugin' is not loaded
Error 1396 Operation ALTER USER failed for 'foo'@'%'
alter user foo identified with 'mysql_old_password';
select * from mysql.user where user = 'foo';
......
install soname 'auth_socket';
install soname 'auth_ed25519';
create user USER identified via unix_socket OR mysql_native_password as password("GOOD");
create user mysqltest1 identified via unix_socket OR mysql_native_password as password("good");
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA unix_socket OR mysql_native_password USING '*8409037B3E362D6DAE24C8E667F4D3B66716144E'
# name match = ok
select user(), current_user(), database();
user() current_user() database()
USER@localhost USER@% test
# name does not match, password good = ok
select user(), current_user(), database();
user() current_user() database()
mysqltest1@localhost mysqltest1@% test
# name does not match, password bad = failure
drop user USER, mysqltest1;
create user USER identified via mysql_native_password as password("GOOD") OR unix_socket;
create user mysqltest1 identified via mysql_native_password as password("good") OR unix_socket;
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA mysql_native_password USING '*8409037B3E362D6DAE24C8E667F4D3B66716144E' OR unix_socket
# name match = ok
select user(), current_user(), database();
user() current_user() database()
USER@localhost USER@% test
# name does not match, password good = ok
select user(), current_user(), database();
user() current_user() database()
mysqltest1@localhost mysqltest1@% test
# name does not match, password bad = failure
drop user USER, mysqltest1;
create user USER identified via unix_socket OR ed25519 as password("GOOD");
create user mysqltest1 identified via unix_socket OR ed25519 as password("good");
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA unix_socket OR ed25519 USING 'F4aF8bw7130VaRbdLCl4f/P/wkjDmgJXwWvpJ5gmsZc'
# name match = ok
select user(), current_user(), database();
user() current_user() database()
USER@localhost USER@% test
# name does not match, password good = ok
select user(), current_user(), database();
user() current_user() database()
mysqltest1@localhost mysqltest1@% test
# name does not match, password bad = failure
drop user USER, mysqltest1;
create user USER identified via ed25519 as password("GOOD") OR unix_socket;
create user mysqltest1 identified via ed25519 as password("good") OR unix_socket;
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA ed25519 USING 'F4aF8bw7130VaRbdLCl4f/P/wkjDmgJXwWvpJ5gmsZc' OR unix_socket
# name match = ok
select user(), current_user(), database();
user() current_user() database()
USER@localhost USER@% test
# name does not match, password good = ok
select user(), current_user(), database();
user() current_user() database()
mysqltest1@localhost mysqltest1@% test
# name does not match, password bad = failure
drop user USER, mysqltest1;
create user USER identified via ed25519 as password("GOOD") OR unix_socket OR mysql_native_password as password("works");
create user mysqltest1 identified via ed25519 as password("good") OR unix_socket OR mysql_native_password as password("works");
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA ed25519 USING 'F4aF8bw7130VaRbdLCl4f/P/wkjDmgJXwWvpJ5gmsZc' OR unix_socket OR mysql_native_password USING '*7D8C3DF236D9163B6C274A9D47704BC496988460'
# name match = ok
select user(), current_user(), database();
user() current_user() database()
USER@localhost USER@% test
# name does not match, password good = ok
select user(), current_user(), database();
user() current_user() database()
mysqltest1@localhost mysqltest1@% test
# name does not match, second password works = ok
select user(), current_user(), database();
user() current_user() database()
mysqltest1@localhost mysqltest1@% test
# name does not match, password bad = failure
drop user USER, mysqltest1;
create user mysqltest1 identified via mysql_native_password as password("good") OR mysql_native_password as password("works");
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA mysql_native_password USING '*8409037B3E362D6DAE24C8E667F4D3B66716144E' OR mysql_native_password USING '*7D8C3DF236D9163B6C274A9D47704BC496988460'
# password good = ok
select user(), current_user(), database();
user() current_user() database()
mysqltest1@localhost mysqltest1@% test
# second password works = ok
select user(), current_user(), database();
user() current_user() database()
mysqltest1@localhost mysqltest1@% test
# password bad = failure
drop user mysqltest1;
create user mysqltest1 identified via ed25519 as password("good") OR unix_socket OR mysql_native_password as password("works");
show grants for mysqltest1;
Grants for mysqltest1@%
GRANT USAGE ON *.* TO 'mysqltest1'@'%' IDENTIFIED VIA ed25519 USING 'F4aF8bw7130VaRbdLCl4f/P/wkjDmgJXwWvpJ5gmsZc' OR unix_socket OR mysql_native_password USING '*7D8C3DF236D9163B6C274A9D47704BC496988460'
select json_detailed(priv) from mysql.global_priv where user='mysqltest1';
json_detailed(priv)
{
"access": 0,
"plugin": "mysql_native_password",
"authentication_string": "*7D8C3DF236D9163B6C274A9D47704BC496988460",
"auth_or":
[
{
"plugin": "ed25519",
"authentication_string": "F4aF8bw7130VaRbdLCl4f/P/wkjDmgJXwWvpJ5gmsZc"
},
{
"plugin": "unix_socket"
},
{
}
]
}
select password,plugin,authentication_string from mysql.user where user='mysqltest1';
Password plugin authentication_string
*7D8C3DF236D9163B6C274A9D47704BC496988460 mysql_native_password *7D8C3DF236D9163B6C274A9D47704BC496988460
flush privileges;
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA ed25519 USING 'F4aF8bw7130VaRbdLCl4f/P/wkjDmgJXwWvpJ5gmsZc' OR unix_socket OR mysql_native_password USING '*7D8C3DF236D9163B6C274A9D47704BC496988460'
set password for mysqltest1 = password('foobar');
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA ed25519 USING 'qv2mG6HWCuy32Slb5xhV4THStewNz2VINVPbgk+XAJ8' OR unix_socket OR mysql_native_password USING '*7D8C3DF236D9163B6C274A9D47704BC496988460'
alter user mysqltest1 identified via unix_socket OR mysql_native_password as password("some");
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA unix_socket OR mysql_native_password USING '*BFE3F4604CFD21E6595080A261D92EF0183B5971'
set password for mysqltest1 = password('foobar');
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA unix_socket OR mysql_native_password USING '*9B500343BC52E2911172EB52AE5CF4847604C6E5'
alter user mysqltest1 identified via unix_socket;
set password for mysqltest1 = password('bla');
ERROR HY000: SET PASSWORD is ignored for users authenticating via unix_socket plugin
alter user mysqltest1 identified via mysql_native_password as password("some") or unix_socket;
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA mysql_native_password USING '*BFE3F4604CFD21E6595080A261D92EF0183B5971' OR unix_socket
drop user mysqltest1;
create user mysqltest1 identified via ed25519 as password("good") OR unix_socket OR mysql_native_password as password("works");
ERROR HY000: Column count of mysql.user is wrong. Expected 3, found 47. Created with MariaDB XX.YY.ZZ, now running XX.YY.ZZ. Please use mysql_upgrade to fix this error
create user USER identified via mysql_native_password as '1234567890123456789012345678901234567890a' OR unix_socket;
create user mysqltest1 identified via mysql_native_password as '1234567890123456789012345678901234567890a' OR unix_socket;
update mysql.global_priv set priv=replace(priv, '1234567890123456789012345678901234567890a', 'invalid password');
flush privileges;
show create user mysqltest1;
CREATE USER for mysqltest1@%
CREATE USER 'mysqltest1'@'%' IDENTIFIED VIA mysql_native_password USING 'invalid password' OR unix_socket
# name match = ok
select user(), current_user(), database();
user() current_user() database()
USER@localhost USER@% test
# name does not match = failure
# SET PASSWORD helps
set password for mysqltest1 = password('bla');
select user(), current_user(), database();
user() current_user() database()
mysqltest1@localhost mysqltest1@% test
drop user USER, mysqltest1;
uninstall soname 'auth_socket';
uninstall soname 'auth_ed25519';
#
# MDEV-11340 Allow multiple alternative authentication methods for the same user
#
--source include/have_unix_socket.inc
if (`SELECT '$USER' = 'mysqltest1'`) {
skip USER is mysqltest1;
}
if (!$AUTH_ED25519_SO) {
skip No auth_ed25519 plugin;
}
--let $plugindir=`SELECT @@global.plugin_dir`
install soname 'auth_socket';
install soname 'auth_ed25519';
--let $try_auth=$MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/peercred_test.txt
--write_file $MYSQLTEST_VARDIR/tmp/peercred_test.txt
--let $replace1=$USER@localhost
--let $replace2=$USER@%
--replace_result $replace1 "USER@localhost" $replace2 "USER@%"
select user(), current_user(), database();
EOF
--let $creplace=create user $USER
--let $dreplace=drop user $USER
#
# socket,password
#
--replace_result $creplace "create user USER"
eval $creplace identified via unix_socket OR mysql_native_password as password("GOOD");
create user mysqltest1 identified via unix_socket OR mysql_native_password as password("good");
show create user mysqltest1;
--echo # name match = ok
--exec $try_auth -u $USER
--echo # name does not match, password good = ok
--exec $try_auth -u mysqltest1 -pgood
--echo # name does not match, password bad = failure
--error 1
--exec $try_auth -u mysqltest1 -pbad
--replace_result $dreplace "drop user USER"
eval $dreplace, mysqltest1;
#
# password,socket
#
--replace_result $creplace "create user USER"
eval $creplace identified via mysql_native_password as password("GOOD") OR unix_socket;
create user mysqltest1 identified via mysql_native_password as password("good") OR unix_socket;
show create user mysqltest1;
--echo # name match = ok
--exec $try_auth -u $USER
--echo # name does not match, password good = ok
--exec $try_auth -u mysqltest1 -pgood
--echo # name does not match, password bad = failure
--error 1
--exec $try_auth -u mysqltest1 -pbad
--replace_result $dreplace "drop user USER"
eval $dreplace, mysqltest1;
#
# socket,ed25519
#
--replace_result $creplace "create user USER"
eval $creplace identified via unix_socket OR ed25519 as password("GOOD");
create user mysqltest1 identified via unix_socket OR ed25519 as password("good");
show create user mysqltest1;
--echo # name match = ok
--exec $try_auth -u $USER
--echo # name does not match, password good = ok
--exec $try_auth -u mysqltest1 -pgood
--echo # name does not match, password bad = failure
--error 1
--exec $try_auth -u mysqltest1 -pbad
--replace_result $dreplace "drop user USER"
eval $dreplace, mysqltest1;
#
# ed25519,socket
#
--replace_result $creplace "create user USER"
eval $creplace identified via ed25519 as password("GOOD") OR unix_socket;
create user mysqltest1 identified via ed25519 as password("good") OR unix_socket;
show create user mysqltest1;
--echo # name match = ok
--exec $try_auth -u $USER
--echo # name does not match, password good = ok
--exec $try_auth -u mysqltest1 -pgood
--echo # name does not match, password bad = failure
--error 1
--exec $try_auth -u mysqltest1 -pbad
--replace_result $dreplace "drop user USER"
eval $dreplace, mysqltest1;
#
# ed25519,socket,password
#
--replace_result $creplace "create user USER"
eval $creplace identified via ed25519 as password("GOOD") OR unix_socket OR mysql_native_password as password("works");
create user mysqltest1 identified via ed25519 as password("good") OR unix_socket OR mysql_native_password as password("works");
show create user mysqltest1;
--echo # name match = ok
--exec $try_auth -u $USER
--echo # name does not match, password good = ok
--exec $try_auth -u mysqltest1 -pgood
--echo # name does not match, second password works = ok
--exec $try_auth -u mysqltest1 -pworks
--echo # name does not match, password bad = failure
--error 1
--exec $try_auth -u mysqltest1 -pbad
--replace_result $dreplace "drop user USER"
eval $dreplace, mysqltest1;
#
# password,password
#
create user mysqltest1 identified via mysql_native_password as password("good") OR mysql_native_password as password("works");
show create user mysqltest1;
--echo # password good = ok
--exec $try_auth -u mysqltest1 -pgood
--echo # second password works = ok
--exec $try_auth -u mysqltest1 -pworks
--echo # password bad = failure
--error 1
--exec $try_auth -u mysqltest1 -pbad
drop user mysqltest1;
#
# show grants, flush privileges, set password, alter user
#
create user mysqltest1 identified via ed25519 as password("good") OR unix_socket OR mysql_native_password as password("works");
show grants for mysqltest1;
select json_detailed(priv) from mysql.global_priv where user='mysqltest1';
select password,plugin,authentication_string from mysql.user where user='mysqltest1';
flush privileges;
show create user mysqltest1;
set password for mysqltest1 = password('foobar');
show create user mysqltest1;
alter user mysqltest1 identified via unix_socket OR mysql_native_password as password("some");
show create user mysqltest1;
set password for mysqltest1 = password('foobar');
show create user mysqltest1;
alter user mysqltest1 identified via unix_socket;
--error ER_SET_PASSWORD_AUTH_PLUGIN
set password for mysqltest1 = password('bla');
alter user mysqltest1 identified via mysql_native_password as password("some") or unix_socket;
show create user mysqltest1;
drop user mysqltest1;
--source include/switch_to_mysql_user.inc
--replace_regex /\d{6}/XX.YY.ZZ/
--error ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE
create user mysqltest1 identified via ed25519 as password("good") OR unix_socket OR mysql_native_password as password("works");
--source include/switch_to_mysql_global_priv.inc
#
# invalid password,socket
#
--replace_result $creplace "create user USER"
eval $creplace identified via mysql_native_password as '1234567890123456789012345678901234567890a' OR unix_socket;
create user mysqltest1 identified via mysql_native_password as '1234567890123456789012345678901234567890a' OR unix_socket;
update mysql.global_priv set priv=replace(priv, '1234567890123456789012345678901234567890a', 'invalid password');
flush privileges;
show create user mysqltest1;
--echo # name match = ok
--exec $try_auth -u $USER
--echo # name does not match = failure
--error 1
--exec $try_auth -u mysqltest1
--echo # SET PASSWORD helps
set password for mysqltest1 = password('bla');
--exec $try_auth -u mysqltest1 -pbla
--replace_result $dreplace "drop user USER"
eval $dreplace, mysqltest1;
uninstall soname 'auth_socket';
uninstall soname 'auth_ed25519';
--remove_file $MYSQLTEST_VARDIR/tmp/peercred_test.txt
INSTALL SONAME 'auth_gssapi';
Warnings:
Note 1105 SSPI: using principal name 'localhost', mech 'Negotiate'
CREATE USER 'nosuchuser' IDENTIFIED WITH gssapi OR mysql_native_password as password("good");
connect(localhost,nosuchuser,,test,MASTER_MYPORT,MASTER_MYSOCK);
connect con1,localhost,nosuchuser,,;
ERROR 28000: Access denied for user 'nosuchuser'@'localhost' (using password: NO)
connect con1,localhost,nosuchuser,good,;
SELECT USER(),CURRENT_USER();
USER() CURRENT_USER()
nosuchuser@localhost nosuchuser@%
disconnect con1;
connection default;
DROP USER nosuchuser;
CREATE USER 'nosuchuser' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi;
connect(localhost,nosuchuser,,test,MASTER_MYPORT,MASTER_MYSOCK);
connect con1,localhost,nosuchuser,,;
ERROR 28000: GSSAPI name mismatch, requested 'nosuchuser', actual name 'GSSAPI_SHORTNAME'
connect con1,localhost,nosuchuser,good,;
SELECT USER(),CURRENT_USER();
USER() CURRENT_USER()
nosuchuser@localhost nosuchuser@%
disconnect con1;
connection default;
DROP USER nosuchuser;
CREATE USER 'GSSAPI_SHORTNAME' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi;
connect con1,localhost,$GSSAPI_SHORTNAME,,;
SELECT USER(),CURRENT_USER();
USER() CURRENT_USER()
GSSAPI_SHORTNAME@localhost GSSAPI_SHORTNAME@%
disconnect con1;
connection default;
DROP USER 'GSSAPI_SHORTNAME';
UNINSTALL SONAME 'auth_gssapi';
--replace_regex /name '[^']+'/name 'localhost'/
INSTALL SONAME 'auth_gssapi';
# gssapi,password
CREATE USER 'nosuchuser' IDENTIFIED WITH gssapi OR mysql_native_password as password("good");
replace_result $MASTER_MYSOCK MASTER_MYSOCK $MASTER_MYPORT MASTER_MYPORT;
error ER_ACCESS_DENIED_ERROR;
connect (con1,localhost,nosuchuser,,);
connect (con1,localhost,nosuchuser,good,);
SELECT USER(),CURRENT_USER();
disconnect con1;
connection default;
DROP USER nosuchuser;
# password,gssapi
CREATE USER 'nosuchuser' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi;
replace_result $MASTER_MYSOCK MASTER_MYSOCK $MASTER_MYPORT MASTER_MYPORT $GSSAPI_SHORTNAME GSSAPI_SHORTNAME;
error ER_ACCESS_DENIED_ERROR;
connect (con1,localhost,nosuchuser,,);
connect (con1,localhost,nosuchuser,good,);
SELECT USER(),CURRENT_USER();
disconnect con1;
connection default;
DROP USER nosuchuser;
replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME;
eval CREATE USER '$GSSAPI_SHORTNAME' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi;
connect (con1,localhost,$GSSAPI_SHORTNAME,,);
replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME;
SELECT USER(),CURRENT_USER();
disconnect con1;
connection default;
replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME;
eval DROP USER '$GSSAPI_SHORTNAME';
UNINSTALL SONAME 'auth_gssapi';
This diff is collapsed.
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
Copyright (c) 2008, 2018, MariaDB Corporation.
Copyright (c) 2008, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -5577,7 +5577,7 @@ void THD::get_definer(LEX_USER *definer, bool role)
{
definer->user= invoker.user;
definer->host= invoker.host;
definer->reset_auth();
definer->auth= NULL;
}
else
#endif
......
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
Copyright (c) 2008, 2018, MariaDB
Copyright (c) 2008, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -9829,8 +9829,7 @@ void get_default_definer(THD *thd, LEX_USER *definer, bool role)
definer->host.length= strlen(definer->host.str);
}
definer->user.length= strlen(definer->user.str);
definer->reset_auth();
definer->auth= NULL;
}
......@@ -9889,7 +9888,7 @@ LEX_USER *create_definer(THD *thd, LEX_CSTRING *user_name,
definer->user= *user_name;
definer->host= *host_name;
definer->reset_auth();
definer->auth= NULL;
return definer;
}
......
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
Copyright (c) 2010, 2016, MariaDB
Copyright (c) 2010, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -722,6 +722,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
class sp_lex_cursor *sp_cursor_stmt;
LEX_CSTRING *lex_str_ptr;
LEX_USER *lex_user;
USER_AUTH *user_auth;
List<Condition_information_item> *cond_info_list;
List<DYNCALL_CREATE_DEF> *dyncol_def_list;
List<Item> *item_list;
......@@ -1945,6 +1946,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <lex_user> user grant_user grant_role user_or_role current_role
admin_option_for_role user_maybe_role
%type <user_auth> opt_auth_str auth_expression auth_token
%type <charset>
opt_collate
charset_name
......@@ -15520,11 +15523,9 @@ ident_or_text:
user_maybe_role:
ident_or_text
{
if (unlikely(!($$=(LEX_USER*) thd->alloc(sizeof(LEX_USER)))))
if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER)))))
MYSQL_YYABORT;
$$->user = $1;
$$->host= null_clex_str; // User or Role, see get_current_user()
$$->reset_auth();
if (unlikely(check_string_char_length(&$$->user, ER_USERNAME,
username_char_length,
......@@ -15533,10 +15534,9 @@ user_maybe_role:
}
| ident_or_text '@' ident_or_text
{
if (unlikely(!($$=(LEX_USER*) thd->alloc(sizeof(LEX_USER)))))
if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER)))))
MYSQL_YYABORT;
$$->user = $1; $$->host=$3;
$$->reset_auth();
if (unlikely(check_string_char_length(&$$->user, ER_USERNAME,
username_char_length,
......@@ -15566,8 +15566,7 @@ user_maybe_role:
if (unlikely(!($$=(LEX_USER*)thd->calloc(sizeof(LEX_USER)))))
MYSQL_YYABORT;
$$->user= current_user;
$$->plugin= empty_clex_str;
$$->auth= empty_clex_str;
$$->auth= new (thd->mem_root) USER_AUTH();
}
;
......@@ -16550,21 +16549,29 @@ opt_for_user:
thd->calloc(sizeof(LEX_USER)))))
MYSQL_YYABORT;
lex->definer->user= current_user;
lex->definer->plugin= empty_clex_str;
lex->definer->auth= empty_clex_str;
lex->definer->auth= new (thd->mem_root) USER_AUTH();
}
| FOR_SYM user equal { Lex->definer= $2; }
;
text_or_password:
TEXT_STRING { Lex->definer->auth= $1;}
| PASSWORD_SYM '(' TEXT_STRING ')' { Lex->definer->pwtext= $3; }
TEXT_STRING
{
Lex->definer->auth= new (thd->mem_root) USER_AUTH();
Lex->definer->auth->auth_str= $1;
}
| PASSWORD_SYM '(' TEXT_STRING ')'
{
Lex->definer->auth= new (thd->mem_root) USER_AUTH();
Lex->definer->auth->pwtext= $3;
}
| OLD_PASSWORD_SYM '(' TEXT_STRING ')'
{
Lex->definer->pwtext= $3;
Lex->definer->auth.str= Item_func_password::alloc(thd,
Lex->definer->auth= new (thd->mem_root) USER_AUTH();
Lex->definer->auth->pwtext= $3;
Lex->definer->auth->auth_str.str= Item_func_password::alloc(thd,
$3.str, $3.length, Item_func_password::OLD);
Lex->definer->auth.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
Lex->definer->auth->auth_str.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
}
;
......@@ -16938,7 +16945,7 @@ current_role:
if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER)))))
MYSQL_YYABORT;
$$->user= current_role;
$$->reset_auth();
$$->auth= NULL;
}
;
......@@ -16955,7 +16962,7 @@ grant_role:
MYSQL_YYABORT;
$$->user= $1;
$$->host= empty_clex_str;
$$->reset_auth();
$$->auth= NULL;
if (unlikely(check_string_char_length(&$$->user, ER_USERNAME,
username_char_length,
......@@ -17152,37 +17159,65 @@ grant_user:
user IDENTIFIED_SYM BY TEXT_STRING
{
$$= $1;
$1->pwtext= $4;
$1->auth= new (thd->mem_root) USER_AUTH();
$1->auth->pwtext= $4;
}
| user IDENTIFIED_SYM BY PASSWORD_SYM TEXT_STRING
{
$$= $1;
$1->auth= $5;
$1->auth= new (thd->mem_root) USER_AUTH();
$1->auth->auth_str= $5;
}
| user IDENTIFIED_SYM via_or_with ident_or_text
| user IDENTIFIED_SYM via_or_with auth_expression
{
$$= $1;
$1->plugin= $4;
$1->auth= empty_clex_str;
$1->auth= $4;
}
| user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
TEXT_STRING_sys
| user_or_role
{ $$= $1; }
;
auth_expression:
auth_token OR_SYM auth_expression
{
$$= $1;
$1->plugin= $4;
$1->auth= $6;
DBUG_ASSERT($$->next == NULL);
$$->next= $3;
}
| user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
PASSWORD_SYM '(' TEXT_STRING ')'
| auth_token
{
$$= $1;
$1->plugin= $4;
$1->pwtext= $8;
}
| user_or_role
{ $$= $1; }
;
auth_token:
ident_or_text opt_auth_str
{
$$= $2;
$$->plugin= $1;
}
;
opt_auth_str:
/* empty */
{
if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH))))
MYSQL_YYABORT;
}
| using_or_as TEXT_STRING_sys
{
if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH))))
MYSQL_YYABORT;
$$->auth_str= $2;
}
| using_or_as PASSWORD_SYM '(' TEXT_STRING ')'
{
if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH))))
MYSQL_YYABORT;
$$->pwtext= $4;
}
;
opt_column_list:
/* empty */
{
......
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
Copyright (c) 2010, 2016, MariaDB
Copyright (c) 2010, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -218,6 +218,7 @@ void ORAerror(THD *thd, const char *s)
class sp_lex_cursor *sp_cursor_stmt;
LEX_CSTRING *lex_str_ptr;
LEX_USER *lex_user;
USER_AUTH *user_auth;
List<Condition_information_item> *cond_info_list;
List<DYNCALL_CREATE_DEF> *dyncol_def_list;
List<Item> *item_list;
......@@ -1449,6 +1450,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <lex_user> user grant_user grant_role user_or_role current_role
admin_option_for_role user_maybe_role
%type <user_auth> opt_auth_str auth_expression auth_token
%type <charset>
opt_collate
charset_name
......@@ -15595,11 +15598,9 @@ ident_or_text:
user_maybe_role:
ident_or_text
{
if (unlikely(!($$=(LEX_USER*) thd->alloc(sizeof(LEX_USER)))))
if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER)))))
MYSQL_YYABORT;
$$->user = $1;
$$->host= null_clex_str; // User or Role, see get_current_user()
$$->reset_auth();
if (unlikely(check_string_char_length(&$$->user, ER_USERNAME,
username_char_length,
......@@ -15608,10 +15609,9 @@ user_maybe_role:
}
| ident_or_text '@' ident_or_text
{
if (unlikely(!($$=(LEX_USER*) thd->alloc(sizeof(LEX_USER)))))
if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER)))))
MYSQL_YYABORT;
$$->user = $1; $$->host=$3;
$$->reset_auth();
if (unlikely(check_string_char_length(&$$->user, ER_USERNAME,
username_char_length,
......@@ -15641,8 +15641,7 @@ user_maybe_role:
if (unlikely(!($$=(LEX_USER*)thd->calloc(sizeof(LEX_USER)))))
MYSQL_YYABORT;
$$->user= current_user;
$$->plugin= empty_clex_str;
$$->auth= empty_clex_str;
$$->auth= new (thd->mem_root) USER_AUTH();
}
;
......@@ -16687,21 +16686,29 @@ opt_for_user:
thd->calloc(sizeof(LEX_USER)))))
MYSQL_YYABORT;
lex->definer->user= current_user;
lex->definer->plugin= empty_clex_str;
lex->definer->auth= empty_clex_str;
lex->definer->auth= new (thd->mem_root) USER_AUTH();
}
| FOR_SYM user equal { Lex->definer= $2; }
;
text_or_password:
TEXT_STRING { Lex->definer->auth= $1;}
| PASSWORD_SYM '(' TEXT_STRING ')' { Lex->definer->pwtext= $3; }
TEXT_STRING
{
Lex->definer->auth= new (thd->mem_root) USER_AUTH();
Lex->definer->auth->auth_str= $1;
}
| PASSWORD_SYM '(' TEXT_STRING ')'
{
Lex->definer->auth= new (thd->mem_root) USER_AUTH();
Lex->definer->auth->pwtext= $3;
}
| OLD_PASSWORD_SYM '(' TEXT_STRING ')'
{
Lex->definer->pwtext= $3;
Lex->definer->auth.str= Item_func_password::alloc(thd,
Lex->definer->auth= new (thd->mem_root) USER_AUTH();
Lex->definer->auth->pwtext= $3;
Lex->definer->auth->auth_str.str= Item_func_password::alloc(thd,
$3.str, $3.length, Item_func_password::OLD);
Lex->definer->auth.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
Lex->definer->auth->auth_str.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
}
;
......@@ -17075,7 +17082,7 @@ current_role:
if (unlikely(!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER)))))
MYSQL_YYABORT;
$$->user= current_role;
$$->reset_auth();
$$->auth= NULL;
}
;
......@@ -17092,7 +17099,7 @@ grant_role:
MYSQL_YYABORT;
$$->user= $1;
$$->host= empty_clex_str;
$$->reset_auth();
$$->auth= NULL;
if (unlikely(check_string_char_length(&$$->user, ER_USERNAME,
username_char_length,
......@@ -17289,35 +17296,63 @@ grant_user:
user IDENTIFIED_SYM BY TEXT_STRING
{
$$= $1;
$1->pwtext= $4;
$1->auth= new (thd->mem_root) USER_AUTH();
$1->auth->pwtext= $4;
}
| user IDENTIFIED_SYM BY PASSWORD_SYM TEXT_STRING
{
$$= $1;
$1->auth= $5;
$1->auth= new (thd->mem_root) USER_AUTH();
$1->auth->auth_str= $5;
}
| user IDENTIFIED_SYM via_or_with ident_or_text
| user IDENTIFIED_SYM via_or_with auth_expression
{
$$= $1;
$1->plugin= $4;
$1->auth= empty_clex_str;
$1->auth= $4;
}
| user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
TEXT_STRING_sys
| user_or_role
{ $$= $1; }
;
auth_expression:
auth_token OR_SYM auth_expression
{
$$= $1;
$1->plugin= $4;
$1->auth= $6;
DBUG_ASSERT($$->next == NULL);
$$->next= $3;
}
| user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
PASSWORD_SYM '(' TEXT_STRING ')'
| auth_token
{
$$= $1;
$1->plugin= $4;
$1->pwtext= $8;
}
| user_or_role
{ $$= $1; }
;
auth_token:
ident_or_text opt_auth_str
{
$$= $2;
$$->plugin= $1;
}
;
opt_auth_str:
/* empty */
{
if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH))))
MYSQL_YYABORT;
}
| using_or_as TEXT_STRING_sys
{
if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH))))
MYSQL_YYABORT;
$$->auth_str= $2;
}
| using_or_as PASSWORD_SYM '(' TEXT_STRING ')'
{
if (!($$=(USER_AUTH*) thd->calloc(sizeof(USER_AUTH))))
MYSQL_YYABORT;
$$->pwtext= $4;
}
;
opt_column_list:
......
#ifndef STRUCTS_INCLUDED
#define STRUCTS_INCLUDED
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2017, MariaDB Corporation.
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates.
Copyright (c) 2009, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -203,6 +203,17 @@ extern const char *show_comp_option_name[];
typedef int *(*update_var)(THD *, struct st_mysql_show_var *);
struct USER_AUTH : public Sql_alloc
{
LEX_CSTRING plugin, auth_str, pwtext;
USER_AUTH *next;
USER_AUTH() : next(NULL)
{
plugin.str= auth_str.str= "";
pwtext.str= NULL;
plugin.length= auth_str.length= pwtext.length= 0;
}
};
struct AUTHID
{
......@@ -227,12 +238,10 @@ struct AUTHID
struct LEX_USER: public AUTHID
{
LEX_CSTRING plugin, auth, pwtext;
void reset_auth()
USER_AUTH *auth;
bool has_auth()
{
pwtext.length= plugin.length= auth.length= 0;
pwtext.str= 0;
plugin.str= auth.str= "";
return auth && (auth->plugin.length || auth->auth_str.length || auth->pwtext.length);
}
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment