1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-07 06:01:31 +03:00

MDEV-13095 Implement User Account locking

Add server support for user account locking.
This patch extends the ALTER/CREATE USER statements for
denying a user's subsequent login attempts:
  ALTER USER
    user [, user2] ACCOUNT [LOCK | UNLOCK]
  CREATE USER
    user [, user2] ACCOUNT [LOCK | UNLOCK]
The SHOW CREATE USER statement was updated to display the
locking state of an user.

Closes #1006
This commit is contained in:
Robert Bindar
2019-02-13 20:02:42 +01:00
committed by Sergei Golubchik
parent d89cdfc229
commit 6c8ce999f8
11 changed files with 419 additions and 5 deletions

View File

@ -0,0 +1,134 @@
create user user1@localhost;
create user user2@localhost;
#
# Only privileged users should be able to lock/unlock.
#
alter user user1@localhost account lock;
alter user user1@localhost account unlock;
create user user3@localhost account lock;
drop user user3@localhost;
connect con1,localhost,user1;
connection con1;
alter user user2@localhost account lock;
ERROR 42000: Access denied; you need (at least one of) the CREATE USER privilege(s) for this operation
disconnect con1;
connection default;
#
# ALTER USER USER1 ACCOUNT LOCK should deny the connection of user1,
# but it should allow user2 to connect.
#
alter user user1@localhost account lock;
connect(localhost,user1,,test,MYSQL_PORT,MYSQL_SOCK);
connect con1,localhost,user1;
ERROR HY000: Access denied, this account is locked
connect con2,localhost,user2;
disconnect con2;
connection default;
alter user user1@localhost account unlock;
#
# Passing an incorrect user should return an error unless
# IF EXISTS is used
#
alter user inexistentUser@localhost account lock;
ERROR HY000: Operation ALTER USER failed for 'inexistentUser'@'localhost'
alter if exists user inexistentUser@localhost account lock;
Warnings:
Error 1133 Can't find any matching row in the user table
Note 1396 Operation ALTER USER failed for 'inexistentUser'@'localhost'
#
# Passing an existing user to CREATE should not be allowed
# and it should not change the locking state of the current user
#
show create user user1@localhost;
CREATE USER for user1@localhost
CREATE USER 'user1'@'localhost'
create user user1@localhost account lock;
ERROR HY000: Operation CREATE USER failed for 'user1'@'localhost'
show create user user1@localhost;
CREATE USER for user1@localhost
CREATE USER 'user1'@'localhost'
#
# Passing multiple users should lock them all
#
alter user user1@localhost, user2@localhost account lock;
connect(localhost,user1,,test,MYSQL_PORT,MYSQL_SOCK);
connect con1,localhost,user1;
ERROR HY000: Access denied, this account is locked
connect(localhost,user2,,test,MYSQL_PORT,MYSQL_SOCK);
connect con2,localhost,user2;
ERROR HY000: Access denied, this account is locked
alter user user1@localhost, user2@localhost account unlock;
#
# The locking state is preserved after acl reload
#
alter user user1@localhost account lock;
flush privileges;
connect(localhost,user1,,test,MYSQL_PORT,MYSQL_SOCK);
connect con1,localhost,user1;
ERROR HY000: Access denied, this account is locked
alter user user1@localhost account unlock;
#
# JSON functions on global_priv reflect the locking state of an account
#
alter user user1@localhost account lock;
select host, user, JSON_VALUE(Priv, '$.account_locked') from mysql.global_priv where user='user1';
host user JSON_VALUE(Priv, '$.account_locked')
localhost user1 1
alter user user1@localhost account unlock;
select host, user, JSON_VALUE(Priv, '$.account_locked') from mysql.global_priv where user='user1';
host user JSON_VALUE(Priv, '$.account_locked')
localhost user1 0
#
# SHOW CREATE USER correctly displays the locking state of an user
#
show create user user1@localhost;
CREATE USER for user1@localhost
CREATE USER 'user1'@'localhost'
alter user user1@localhost account lock;
show create user user1@localhost;
CREATE USER for user1@localhost
CREATE USER 'user1'@'localhost' ACCOUNT LOCK
alter user user1@localhost account unlock;
show create user user1@localhost;
CREATE USER for user1@localhost
CREATE USER 'user1'@'localhost'
create user newuser@localhost account lock;
show create user newuser@localhost;
CREATE USER for newuser@localhost
CREATE USER 'newuser'@'localhost' ACCOUNT LOCK
drop user newuser@localhost;
#
# Users should be able to lock themselves
#
grant CREATE USER on *.* to user1@localhost;
connect con1,localhost,user1;
connection con1;
alter user user1@localhost account lock;
disconnect con1;
connection default;
connect(localhost,user1,,test,MYSQL_PORT,MYSQL_SOCK);
connect con1,localhost,user1;
ERROR HY000: Access denied, this account is locked
alter user user1@localhost account unlock;
#
# Users should be able to unlock themselves if the connections
# had been established before the accounts were locked
#
grant CREATE USER on *.* to user1@localhost;
connect con1,localhost,user1;
alter user user1@localhost account lock;
connection con1;
alter user user1@localhost account unlock;
show create user user1@localhost;
CREATE USER for user1@localhost
CREATE USER 'user1'@'localhost'
disconnect con1;
connection default;
#
# COM_CHANGE_USER should return error if the destination
# account is locked
#
alter user user1@localhost account lock;
ERROR HY000: Access denied, this account is locked
drop user user1@localhost;
drop user user2@localhost;

View File

@ -0,0 +1,142 @@
#
# Test user account locking
#
--source include/not_embedded.inc
create user user1@localhost;
create user user2@localhost;
--echo #
--echo # Only privileged users should be able to lock/unlock.
--echo #
alter user user1@localhost account lock;
alter user user1@localhost account unlock;
create user user3@localhost account lock;
drop user user3@localhost;
connect(con1,localhost,user1);
connection con1;
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
alter user user2@localhost account lock;
disconnect con1;
connection default;
--echo #
--echo # ALTER USER USER1 ACCOUNT LOCK should deny the connection of user1,
--echo # but it should allow user2 to connect.
--echo #
alter user user1@localhost account lock;
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
--error ER_ACCOUNT_HAS_BEEN_LOCKED
connect(con1,localhost,user1);
connect(con2,localhost,user2);
disconnect con2;
connection default;
alter user user1@localhost account unlock;
--echo #
--echo # Passing an incorrect user should return an error unless
--echo # IF EXISTS is used
--echo #
--error ER_CANNOT_USER
alter user inexistentUser@localhost account lock;
alter if exists user inexistentUser@localhost account lock;
--echo #
--echo # Passing an existing user to CREATE should not be allowed
--echo # and it should not change the locking state of the current user
--echo #
show create user user1@localhost;
--error ER_CANNOT_USER
create user user1@localhost account lock;
show create user user1@localhost;
--echo #
--echo # Passing multiple users should lock them all
--echo #
alter user user1@localhost, user2@localhost account lock;
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
--error ER_ACCOUNT_HAS_BEEN_LOCKED
connect(con1,localhost,user1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
--error ER_ACCOUNT_HAS_BEEN_LOCKED
connect(con2,localhost,user2);
alter user user1@localhost, user2@localhost account unlock;
--echo #
--echo # The locking state is preserved after acl reload
--echo #
alter user user1@localhost account lock;
flush privileges;
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
--error ER_ACCOUNT_HAS_BEEN_LOCKED
connect(con1,localhost,user1);
alter user user1@localhost account unlock;
--echo #
--echo # JSON functions on global_priv reflect the locking state of an account
--echo #
alter user user1@localhost account lock;
select host, user, JSON_VALUE(Priv, '$.account_locked') from mysql.global_priv where user='user1';
alter user user1@localhost account unlock;
select host, user, JSON_VALUE(Priv, '$.account_locked') from mysql.global_priv where user='user1';
--echo #
--echo # SHOW CREATE USER correctly displays the locking state of an user
--echo #
show create user user1@localhost;
alter user user1@localhost account lock;
show create user user1@localhost;
alter user user1@localhost account unlock;
show create user user1@localhost;
create user newuser@localhost account lock;
show create user newuser@localhost;
drop user newuser@localhost;
--echo #
--echo # Users should be able to lock themselves
--echo #
grant CREATE USER on *.* to user1@localhost;
connect(con1,localhost,user1);
connection con1;
alter user user1@localhost account lock;
disconnect con1;
connection default;
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
--error ER_ACCOUNT_HAS_BEEN_LOCKED
connect(con1,localhost,user1);
alter user user1@localhost account unlock;
--echo #
--echo # Users should be able to unlock themselves if the connections
--echo # had been established before the accounts were locked
--echo #
grant CREATE USER on *.* to user1@localhost;
connect(con1,localhost,user1);
alter user user1@localhost account lock;
connection con1;
alter user user1@localhost account unlock;
show create user user1@localhost;
disconnect con1;
connection default;
--echo #
--echo # COM_CHANGE_USER should return error if the destination
--echo # account is locked
--echo #
alter user user1@localhost account lock;
--error ER_ACCOUNT_HAS_BEEN_LOCKED
--change_user user1
drop user user1@localhost;
drop user user2@localhost;

View File

@ -165,5 +165,26 @@ foo % Y mysql_native_password *E8D46CE25265E545D225A8A6F1BAF642FEBEE5CB
goo % Y mysql_native_password *F3A2A51A9B0F2BE2468926B4132313728C250DBF goo % Y mysql_native_password *F3A2A51A9B0F2BE2468926B4132313728C250DBF
ioo % Y mysql_old_password 7a8f886d28473e85 ioo % Y mysql_old_password 7a8f886d28473e85
# #
# Test account locking
#
create user user1@localhost account lock;
connect(localhost,user1,,test,MYSQL_PORT,MYSQL_SOCK);
connect con1,localhost,user1;
ERROR HY000: Access denied, this account is locked
flush privileges;
connect(localhost,user1,,test,MYSQL_PORT,MYSQL_SOCK);
connect con1,localhost,user1;
ERROR HY000: Access denied, this account is locked
show create user user1@localhost;
CREATE USER for user1@localhost
CREATE USER 'user1'@'localhost' ACCOUNT LOCK
alter user user1@localhost account unlock;
connect con1,localhost,user1;
disconnect con1;
connection default;
show create user user1@localhost;
CREATE USER for user1@localhost
CREATE USER 'user1'@'localhost'
#
# Reset to final original state. # Reset to final original state.
# #

View File

@ -88,6 +88,24 @@ select user, host, select_priv, plugin, authentication_string from mysql.user
where user like "%oo" where user like "%oo"
order by user; order by user;
--echo #
--echo # Test account locking
--echo #
create user user1@localhost account lock;
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
--error ER_ACCOUNT_HAS_BEEN_LOCKED
connect(con1,localhost,user1);
flush privileges;
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
--error ER_ACCOUNT_HAS_BEEN_LOCKED
connect(con1,localhost,user1);
show create user user1@localhost;
alter user user1@localhost account unlock;
connect(con1,localhost,user1);
disconnect con1;
connection default;
show create user user1@localhost;
--echo # --echo #
--echo # Reset to final original state. --echo # Reset to final original state.
--echo # --echo #

View File

@ -643,6 +643,7 @@ ALTER TABLE user ADD plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL,
ALTER TABLE user MODIFY plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL, ALTER TABLE user MODIFY plugin char(64) CHARACTER SET latin1 DEFAULT '' NOT NULL,
MODIFY authentication_string TEXT NOT NULL; MODIFY authentication_string TEXT NOT NULL;
ALTER TABLE user ADD password_expired ENUM('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; ALTER TABLE user ADD password_expired ENUM('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL;
ALTER TABLE user ADD account_locked enum('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL after password_expired;
ALTER TABLE user ADD is_role enum('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; ALTER TABLE user ADD is_role enum('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL;
ALTER TABLE user ADD default_role char(80) binary DEFAULT '' NOT NULL; ALTER TABLE user ADD default_role char(80) binary DEFAULT '' NOT NULL;
ALTER TABLE user ADD max_statement_time decimal(12,6) DEFAULT 0 NOT NULL; ALTER TABLE user ADD max_statement_time decimal(12,6) DEFAULT 0 NOT NULL;
@ -804,6 +805,7 @@ IF 'BASE TABLE' = (select table_type from information_schema.tables where table_
'max_statement_time', max_statement_time, 'max_statement_time', max_statement_time,
'plugin', if(plugin>'',plugin,if(length(password)=16,'mysql_old_password','mysql_native_password')), 'plugin', if(plugin>'',plugin,if(length(password)=16,'mysql_old_password','mysql_native_password')),
'authentication_string', if(plugin>'' and authentication_string>'',authentication_string,password), 'authentication_string', if(plugin>'' and authentication_string>'',authentication_string,password),
'account_locked', 'Y'=account_locked,
'default_role', default_role, 'default_role', default_role,
'is_role', 'Y'=is_role)) as Priv 'is_role', 'Y'=is_role)) as Priv
FROM user; FROM user;

View File

@ -55,6 +55,7 @@ static SYMBOL symbols[] = {
{ ">>", SYM(SHIFT_RIGHT)}, { ">>", SYM(SHIFT_RIGHT)},
{ "<=>", SYM(EQUAL_SYM)}, { "<=>", SYM(EQUAL_SYM)},
{ "ACCESSIBLE", SYM(ACCESSIBLE_SYM)}, { "ACCESSIBLE", SYM(ACCESSIBLE_SYM)},
{ "ACCOUNT", SYM(ACCOUNT_SYM)},
{ "ACTION", SYM(ACTION)}, { "ACTION", SYM(ACTION)},
{ "ADD", SYM(ADD)}, { "ADD", SYM(ADD)},
{ "ADMIN", SYM(ADMIN_SYM)}, { "ADMIN", SYM(ADMIN_SYM)},

View File

@ -7933,3 +7933,6 @@ ER_BACKUP_UNKNOWN_STAGE
eng "Unknown backup stage: '%s'. Stage should be one of START, FLUSH, BLOCK_DDL, BLOCK_COMMIT or END" eng "Unknown backup stage: '%s'. Stage should be one of START, FLUSH, BLOCK_DDL, BLOCK_COMMIT or END"
ER_USER_IS_BLOCKED ER_USER_IS_BLOCKED
eng "User is blocked because of too many credential errors; unblock with 'FLUSH PRIVILEGES'" eng "User is blocked because of too many credential errors; unblock with 'FLUSH PRIVILEGES'"
ER_ACCOUNT_HAS_BEEN_LOCKED
eng "Access denied, this account is locked"
rum "Acces refuzat, acest cont este blocat"

View File

@ -152,6 +152,7 @@ public:
LEX_CSTRING default_rolename; LEX_CSTRING default_rolename;
struct AUTH { LEX_CSTRING plugin, auth_string, salt; } *auth; struct AUTH { LEX_CSTRING plugin, auth_string, salt; } *auth;
uint nauth; uint nauth;
bool account_locked;
bool alloc_auth(MEM_ROOT *root, uint n) bool alloc_auth(MEM_ROOT *root, uint n)
{ {
@ -864,6 +865,8 @@ class User_table: public Grant_table_base
virtual int set_is_role (bool x) const = 0; virtual int set_is_role (bool x) const = 0;
virtual const char* get_default_role (MEM_ROOT *root) const = 0; virtual const char* get_default_role (MEM_ROOT *root) const = 0;
virtual int set_default_role (const char *s, size_t l) const = 0; virtual int set_default_role (const char *s, size_t l) const = 0;
virtual bool get_account_locked () const = 0;
virtual int set_account_locked (bool x) const = 0;
virtual ~User_table() {} virtual ~User_table() {}
private: private:
@ -1123,7 +1126,22 @@ class User_table_tabular: public User_table
return f->store(s, l, system_charset_info); return f->store(s, l, system_charset_info);
else else
return 1; return 1;
}; }
/* On a MariaDB 10.3 user table, the account locking accessors will try to
get the content of the max_statement_time column, but they will fail due
to the typecheck in get_field. */
bool get_account_locked () const
{
Field *f= get_field(end_priv_columns + 13, MYSQL_TYPE_ENUM);
return f ? f->val_int()-1 : 0;
}
int set_account_locked (bool x) const
{
if (Field *f= get_field(end_priv_columns + 13, MYSQL_TYPE_ENUM))
return f->store(x+1, 0);
else
return 1;
}
virtual ~User_table_tabular() {} virtual ~User_table_tabular() {}
private: private:
@ -1416,6 +1434,10 @@ class User_table_json: public User_table
{ return get_str_value(root, "default_role"); } { return get_str_value(root, "default_role"); }
int set_default_role (const char *s, size_t l) const int set_default_role (const char *s, size_t l) const
{ return set_str_value("default_role", s, l); } { return set_str_value("default_role", s, l); }
bool get_account_locked () const
{ return get_bool_value("account_locked"); }
int set_account_locked (bool x) const
{ return set_bool_value("account_locked", x); }
~User_table_json() {} ~User_table_json() {}
private: private:
@ -2260,6 +2282,8 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
my_init_dynamic_array(&user.role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0)); my_init_dynamic_array(&user.role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0));
user.account_locked= user_table.get_account_locked();
if (is_role) if (is_role)
{ {
if (is_invalid_role_name(username)) if (is_invalid_role_name(username))
@ -4327,6 +4351,13 @@ static int replace_user_table(THD *thd, const User_table &user_table,
mqh_used= (mqh_used || lex->mqh.questions || lex->mqh.updates || mqh_used= (mqh_used || lex->mqh.questions || lex->mqh.updates ||
lex->mqh.conn_per_hour || lex->mqh.user_conn || lex->mqh.conn_per_hour || lex->mqh.user_conn ||
lex->mqh.max_statement_time != 0.0); lex->mqh.max_statement_time != 0.0);
if (lex->account_options.account_locked != ACCOUNTLOCK_UNSPECIFIED)
{
bool lock_value= lex->account_options.account_locked == ACCOUNTLOCK_LOCKED;
user_table.set_account_locked(lock_value);
new_acl_user.account_locked= lock_value;
}
} }
if (old_row_exists) if (old_row_exists)
@ -8780,6 +8811,9 @@ bool mysql_show_create_user(THD *thd, LEX_USER *lex_user)
add_user_parameters(&result, acl_user, false); add_user_parameters(&result, acl_user, false);
if (acl_user->account_locked)
result.append(STRING_WITH_LEN(" ACCOUNT LOCK"));
protocol->prepare_for_resend(); protocol->prepare_for_resend();
protocol->store(result.ptr(), result.length(), result.charset()); protocol->store(result.ptr(), result.length(), result.charset());
if (protocol->write()) if (protocol->write())
@ -13641,6 +13675,12 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (acl_user->account_locked) {
status_var_increment(denied_connections);
my_error(ER_ACCOUNT_HAS_BEEN_LOCKED, MYF(0));
DBUG_RETURN(1);
}
/* /*
Don't allow the user to connect if he has done too many queries. Don't allow the user to connect if he has done too many queries.
As we are testing max_user_connections == 0 here, it means that we As we are testing max_user_connections == 0 here, it means that we

View File

@ -2939,6 +2939,27 @@ public:
Explain_delete* save_explain_delete_data(MEM_ROOT *mem_root, THD *thd); Explain_delete* save_explain_delete_data(MEM_ROOT *mem_root, THD *thd);
}; };
enum account_lock_type
{
ACCOUNTLOCK_UNSPECIFIED,
ACCOUNTLOCK_LOCKED,
ACCOUNTLOCK_UNLOCKED
};
struct Account_options
{
Account_options()
: account_locked(ACCOUNTLOCK_UNSPECIFIED)
{ }
void reset()
{
account_locked= ACCOUNTLOCK_UNSPECIFIED;
}
account_lock_type account_locked;
};
class Query_arena_memroot; class Query_arena_memroot;
/* The state of the lex parsing. This is saved in the THD struct */ /* The state of the lex parsing. This is saved in the THD struct */
@ -3030,6 +3051,9 @@ public:
*/ */
LEX_USER *definer; LEX_USER *definer;
/* Used in ALTER/CREATE user to store account locking options */
Account_options account_options;
Table_type table_type; /* Used for SHOW CREATE */ Table_type table_type; /* Used for SHOW CREATE */
List<Key_part_spec> ref_list; List<Key_part_spec> ref_list;
List<LEX_USER> users_list; List<LEX_USER> users_list;

View File

@ -1151,6 +1151,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
Non-reserved keywords Non-reserved keywords
*/ */
%token <kwd> ACCOUNT_SYM /* MYSQL */
%token <kwd> ACTION /* SQL-2003-N */ %token <kwd> ACTION /* SQL-2003-N */
%token <kwd> ADMIN_SYM /* SQL-2003-N */ %token <kwd> ADMIN_SYM /* SQL-2003-N */
%token <kwd> ADDDATE_SYM /* MYSQL-FUNC */ %token <kwd> ADDDATE_SYM /* MYSQL-FUNC */
@ -2911,7 +2912,7 @@ create:
Lex->pop_select(); //main select Lex->pop_select(); //main select
} }
| create_or_replace USER_SYM opt_if_not_exists clear_privileges | create_or_replace USER_SYM opt_if_not_exists clear_privileges
grant_list opt_require_clause opt_resource_options grant_list opt_require_clause opt_resource_options opt_account_locking
{ {
if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_USER, if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_USER,
$1 | $3))) $1 | $3)))
@ -3318,6 +3319,7 @@ clear_privileges:
lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0; lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
bzero((char *)&(lex->mqh),sizeof(lex->mqh)); bzero((char *)&(lex->mqh),sizeof(lex->mqh));
lex->account_options.reset();
} }
; ;
@ -7979,7 +7981,7 @@ alter:
} OPTIONS_SYM '(' server_options_list ')' { } } OPTIONS_SYM '(' server_options_list ')' { }
/* ALTER USER foo is allowed for MySQL compatibility. */ /* ALTER USER foo is allowed for MySQL compatibility. */
| ALTER opt_if_exists USER_SYM clear_privileges grant_list | ALTER opt_if_exists USER_SYM clear_privileges grant_list
opt_require_clause opt_resource_options opt_require_clause opt_resource_options opt_account_locking
{ {
Lex->create_info.set($2); Lex->create_info.set($2);
Lex->sql_command= SQLCOM_ALTER_USER; Lex->sql_command= SQLCOM_ALTER_USER;
@ -8018,6 +8020,18 @@ alter:
} }
; ;
opt_account_locking:
/* Nothing */ {}
| ACCOUNT_SYM LOCK_SYM
{
Lex->account_options.account_locked= ACCOUNTLOCK_LOCKED;
}
| ACCOUNT_SYM UNLOCK_SYM
{
Lex->account_options.account_locked= ACCOUNTLOCK_UNLOCKED;
}
;
ev_alter_on_schedule_completion: ev_alter_on_schedule_completion:
/* empty */ { $$= 0;} /* empty */ { $$= 0;}
| ON SCHEDULE_SYM ev_schedule_time { $$= 1; } | ON SCHEDULE_SYM ev_schedule_time { $$= 1; }
@ -15855,6 +15869,7 @@ keyword_data_type:
*/ */
keyword_sp_var_and_label: keyword_sp_var_and_label:
ACTION ACTION
| ACCOUNT_SYM
| ADDDATE_SYM | ADDDATE_SYM
| ADMIN_SYM | ADMIN_SYM
| AFTER_SYM | AFTER_SYM

View File

@ -646,6 +646,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
Non-reserved keywords Non-reserved keywords
*/ */
%token <kwd> ACCOUNT_SYM /* MYSQL */
%token <kwd> ACTION /* SQL-2003-N */ %token <kwd> ACTION /* SQL-2003-N */
%token <kwd> ADMIN_SYM /* SQL-2003-N */ %token <kwd> ADMIN_SYM /* SQL-2003-N */
%token <kwd> ADDDATE_SYM /* MYSQL-FUNC */ %token <kwd> ADDDATE_SYM /* MYSQL-FUNC */
@ -2417,7 +2418,7 @@ create:
Lex->pop_select(); //main select Lex->pop_select(); //main select
} }
| create_or_replace USER_SYM opt_if_not_exists clear_privileges | create_or_replace USER_SYM opt_if_not_exists clear_privileges
grant_list opt_require_clause opt_resource_options grant_list opt_require_clause opt_resource_options opt_account_locking
{ {
if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_USER, if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_USER,
$1 | $3))) $1 | $3)))
@ -8009,7 +8010,7 @@ alter:
} OPTIONS_SYM '(' server_options_list ')' { } } OPTIONS_SYM '(' server_options_list ')' { }
/* ALTER USER foo is allowed for MySQL compatibility. */ /* ALTER USER foo is allowed for MySQL compatibility. */
| ALTER opt_if_exists USER_SYM clear_privileges grant_list | ALTER opt_if_exists USER_SYM clear_privileges grant_list
opt_require_clause opt_resource_options opt_require_clause opt_resource_options opt_account_locking
{ {
Lex->create_info.set($2); Lex->create_info.set($2);
Lex->sql_command= SQLCOM_ALTER_USER; Lex->sql_command= SQLCOM_ALTER_USER;
@ -8048,6 +8049,18 @@ alter:
} }
; ;
opt_account_locking:
/* Nothing */ {}
| ACCOUNT_SYM LOCK_SYM
{
Lex->account_options.account_locked= ACCOUNTLOCK_LOCKED;
}
| ACCOUNT_SYM UNLOCK_SYM
{
Lex->account_options.account_locked= ACCOUNTLOCK_UNLOCKED;
}
;
ev_alter_on_schedule_completion: ev_alter_on_schedule_completion:
/* empty */ { $$= 0;} /* empty */ { $$= 0;}
| ON SCHEDULE_SYM ev_schedule_time { $$= 1; } | ON SCHEDULE_SYM ev_schedule_time { $$= 1; }
@ -15943,6 +15956,7 @@ keyword_data_type:
*/ */
keyword_sp_var_and_label: keyword_sp_var_and_label:
ACTION ACTION
| ACCOUNT_SYM
| ADDDATE_SYM | ADDDATE_SYM
| ADMIN_SYM | ADMIN_SYM
| AFTER_SYM | AFTER_SYM