Commit 68f390e5 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables

parent 305cffeb
#
# MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
#
# Test that "SET gtid_binlog_state" is not allowed without REPLICATION MASTER ADMIN or SUPER
CREATE USER user1@localhost;
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
REVOKE REPLICATION MASTER ADMIN, SUPER ON *.* FROM user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_binlog_state='0-1-10';
ERROR 42000: Access denied; you need (at least one of) the SUPER, REPLICATION MASTER ADMIN privilege(s) for this operation
SET gtid_binlog_state='0-1-10';
ERROR HY000: Variable 'gtid_binlog_state' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_binlog_state='0-1-10';
ERROR HY000: Variable 'gtid_binlog_state' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_binlog_state" is allowed with REPLICATION MASTER ADMIN
CREATE USER user1@localhost;
GRANT REPLICATION MASTER ADMIN ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_binlog_state='0-1-10';
ERROR HY000: Binlog closed, cannot RESET MASTER
SET gtid_binlog_state='0-1-10';
ERROR HY000: Variable 'gtid_binlog_state' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_binlog_state='0-1-10';
ERROR HY000: Variable 'gtid_binlog_state' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_binlog_state" is allowed with SUPER
CREATE USER user1@localhost;
GRANT SUPER ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_binlog_state='0-1-10';
ERROR HY000: Binlog closed, cannot RESET MASTER
SET gtid_binlog_state='0-1-10';
ERROR HY000: Variable 'gtid_binlog_state' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_binlog_state='0-1-10';
ERROR HY000: Variable 'gtid_binlog_state' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
#
# MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
#
SET @global=@@global.gtid_cleanup_batch_size;
# Test that "SET gtid_cleanup_batch_size" is not allowed without REPLICATION SLAVE ADMIN or SUPER
CREATE USER user1@localhost;
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
REVOKE REPLICATION SLAVE ADMIN, SUPER ON *.* FROM user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_cleanup_batch_size=1;
ERROR 42000: Access denied; you need (at least one of) the SUPER, REPLICATION SLAVE ADMIN privilege(s) for this operation
SET gtid_cleanup_batch_size=1;
ERROR HY000: Variable 'gtid_cleanup_batch_size' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_cleanup_batch_size=1;
ERROR HY000: Variable 'gtid_cleanup_batch_size' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_cleanup_batch_size" is allowed with REPLICATION SLAVE ADMIN
CREATE USER user1@localhost;
GRANT REPLICATION SLAVE ADMIN ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_cleanup_batch_size=1;
SET gtid_cleanup_batch_size=1;
ERROR HY000: Variable 'gtid_cleanup_batch_size' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_cleanup_batch_size=1;
ERROR HY000: Variable 'gtid_cleanup_batch_size' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_cleanup_batch_size" is allowed with SUPER
CREATE USER user1@localhost;
GRANT SUPER ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_cleanup_batch_size=1;
SET gtid_cleanup_batch_size=1;
ERROR HY000: Variable 'gtid_cleanup_batch_size' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_cleanup_batch_size=1;
ERROR HY000: Variable 'gtid_cleanup_batch_size' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
SET @@global.gtid_cleanup_batch_size=@global;
#
# MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
#
SET @global=@@global.gtid_ignore_duplicates;
# Test that "SET gtid_ignore_duplicates" is not allowed without REPLICATION SLAVE ADMIN or SUPER
CREATE USER user1@localhost;
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
REVOKE REPLICATION SLAVE ADMIN, SUPER ON *.* FROM user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_ignore_duplicates=1;
ERROR 42000: Access denied; you need (at least one of) the SUPER, REPLICATION SLAVE ADMIN privilege(s) for this operation
SET gtid_ignore_duplicates=1;
ERROR HY000: Variable 'gtid_ignore_duplicates' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_ignore_duplicates=1;
ERROR HY000: Variable 'gtid_ignore_duplicates' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_ignore_duplicates" is allowed with REPLICATION SLAVE ADMIN
CREATE USER user1@localhost;
GRANT REPLICATION SLAVE ADMIN ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_ignore_duplicates=1;
SET gtid_ignore_duplicates=1;
ERROR HY000: Variable 'gtid_ignore_duplicates' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_ignore_duplicates=1;
ERROR HY000: Variable 'gtid_ignore_duplicates' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_ignore_duplicates" is allowed with SUPER
CREATE USER user1@localhost;
GRANT SUPER ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_ignore_duplicates=1;
SET gtid_ignore_duplicates=1;
ERROR HY000: Variable 'gtid_ignore_duplicates' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_ignore_duplicates=1;
ERROR HY000: Variable 'gtid_ignore_duplicates' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
SET @@global.gtid_ignore_duplicates=@global;
#
# MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
#
SET @global=@@global.gtid_pos_auto_engines;
# Test that "SET gtid_pos_auto_engines" is not allowed without REPLICATION SLAVE ADMIN or SUPER
CREATE USER user1@localhost;
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
REVOKE REPLICATION SLAVE ADMIN, SUPER ON *.* FROM user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_pos_auto_engines='';
ERROR 42000: Access denied; you need (at least one of) the SUPER, REPLICATION SLAVE ADMIN privilege(s) for this operation
SET gtid_pos_auto_engines='';
ERROR HY000: Variable 'gtid_pos_auto_engines' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_pos_auto_engines='';
ERROR HY000: Variable 'gtid_pos_auto_engines' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_pos_auto_engines" is allowed with REPLICATION SLAVE ADMIN
CREATE USER user1@localhost;
GRANT REPLICATION SLAVE ADMIN ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_pos_auto_engines='';
SET gtid_pos_auto_engines='';
ERROR HY000: Variable 'gtid_pos_auto_engines' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_pos_auto_engines='';
ERROR HY000: Variable 'gtid_pos_auto_engines' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_pos_auto_engines" is allowed with SUPER
CREATE USER user1@localhost;
GRANT SUPER ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_pos_auto_engines='';
SET gtid_pos_auto_engines='';
ERROR HY000: Variable 'gtid_pos_auto_engines' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_pos_auto_engines='';
ERROR HY000: Variable 'gtid_pos_auto_engines' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
SET @@global.gtid_pos_auto_engines=@global;
#
# MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
#
SET @global=@@global.gtid_slave_pos;
# Test that "SET gtid_slave_pos" is not allowed without REPLICATION SLAVE ADMIN or SUPER
CREATE USER user1@localhost;
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
REVOKE REPLICATION SLAVE ADMIN, SUPER ON *.* FROM user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_slave_pos='';
ERROR 42000: Access denied; you need (at least one of) the SUPER, REPLICATION SLAVE ADMIN privilege(s) for this operation
SET gtid_slave_pos='';
ERROR HY000: Variable 'gtid_slave_pos' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_slave_pos='';
ERROR HY000: Variable 'gtid_slave_pos' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_slave_pos" is allowed with REPLICATION SLAVE ADMIN
CREATE USER user1@localhost;
GRANT REPLICATION SLAVE ADMIN ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_slave_pos='';
SET gtid_slave_pos='';
ERROR HY000: Variable 'gtid_slave_pos' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_slave_pos='';
ERROR HY000: Variable 'gtid_slave_pos' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_slave_pos" is allowed with SUPER
CREATE USER user1@localhost;
GRANT SUPER ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_slave_pos='';
SET gtid_slave_pos='';
ERROR HY000: Variable 'gtid_slave_pos' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_slave_pos='';
ERROR HY000: Variable 'gtid_slave_pos' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
SET @@global.gtid_slave_pos=@global;
#
# MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
#
SET @global=@@global.gtid_strict_mode;
# Test that "SET gtid_strict_mode" is not allowed without REPLICATION SLAVE ADMIN or SUPER
CREATE USER user1@localhost;
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
REVOKE REPLICATION SLAVE ADMIN, SUPER ON *.* FROM user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_strict_mode=1;
ERROR 42000: Access denied; you need (at least one of) the SUPER, REPLICATION SLAVE ADMIN privilege(s) for this operation
SET gtid_strict_mode=1;
ERROR HY000: Variable 'gtid_strict_mode' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_strict_mode=1;
ERROR HY000: Variable 'gtid_strict_mode' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_strict_mode" is allowed with REPLICATION SLAVE ADMIN
CREATE USER user1@localhost;
GRANT REPLICATION SLAVE ADMIN ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_strict_mode=1;
SET gtid_strict_mode=1;
ERROR HY000: Variable 'gtid_strict_mode' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_strict_mode=1;
ERROR HY000: Variable 'gtid_strict_mode' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
# Test that "SET gtid_strict_mode" is allowed with SUPER
CREATE USER user1@localhost;
GRANT SUPER ON *.* TO user1@localhost;
connect user1,localhost,user1,,;
connection user1;
SET GLOBAL gtid_strict_mode=1;
SET gtid_strict_mode=1;
ERROR HY000: Variable 'gtid_strict_mode' is a GLOBAL variable and should be set with SET GLOBAL
SET SESSION gtid_strict_mode=1;
ERROR HY000: Variable 'gtid_strict_mode' is a GLOBAL variable and should be set with SET GLOBAL
disconnect user1;
connection default;
DROP USER user1@localhost;
SET @@global.gtid_strict_mode=@global;
--source include/not_embedded.inc
--echo #
--echo # MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
--echo #
#
# Binlog is not opened in this test.
# So the test returns "access denied" on the lack of privileges,
# or "Binlog closed, cannot RESET MASTER" on success.
#
--let var = gtid_binlog_state
--let grant = REPLICATION MASTER ADMIN
--let value = '0-1-10'
--echo # Test that "SET $var" is not allowed without $grant or SUPER
CREATE USER user1@localhost;
GRANT ALL PRIVILEGES ON *.* TO user1@localhost;
--eval REVOKE $grant, SUPER ON *.* FROM user1@localhost
--connect(user1,localhost,user1,,)
--connection user1
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
--eval SET GLOBAL $var=$value
--error ER_GLOBAL_VARIABLE
--eval SET $var=$value
--error ER_GLOBAL_VARIABLE
--eval SET SESSION $var=$value
--disconnect user1
--connection default
DROP USER user1@localhost;
--echo # Test that "SET $var" is allowed with $grant
CREATE USER user1@localhost;
--eval GRANT $grant ON *.* TO user1@localhost
--connect(user1,localhost,user1,,)
--connection user1
--error ER_FLUSH_MASTER_BINLOG_CLOSED
--eval SET GLOBAL $var=$value
--error ER_GLOBAL_VARIABLE
--eval SET $var=$value
--error ER_GLOBAL_VARIABLE
--eval SET SESSION $var=$value
--disconnect user1
--connection default
DROP USER user1@localhost;
--echo # Test that "SET $var" is allowed with SUPER
CREATE USER user1@localhost;
GRANT SUPER ON *.* TO user1@localhost;
--connect(user1,localhost,user1,,)
--connection user1
--error ER_FLUSH_MASTER_BINLOG_CLOSED
--eval SET GLOBAL $var=$value
--error ER_GLOBAL_VARIABLE
--eval SET $var=$value
--error ER_GLOBAL_VARIABLE
--eval SET SESSION $var=$value
--disconnect user1
--connection default
DROP USER user1@localhost;
--echo #
--echo # MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
--echo #
--let var = gtid_cleanup_batch_size
--let grant = REPLICATION SLAVE ADMIN
--let value = 1
--source suite/sys_vars/inc/sysvar_global_grant.inc
--echo #
--echo # MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
--echo #
--let var = gtid_ignore_duplicates
--let grant = REPLICATION SLAVE ADMIN
--let value = 1
--source suite/sys_vars/inc/sysvar_global_grant.inc
--echo #
--echo # MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
--echo #
--let var = gtid_pos_auto_engines
--let grant = REPLICATION SLAVE ADMIN
--let value = ''
--source suite/sys_vars/inc/sysvar_global_grant.inc
--echo #
--echo # MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
--echo #
--let var = gtid_slave_pos
--let grant = REPLICATION SLAVE ADMIN
--let value = ''
--source suite/sys_vars/inc/sysvar_global_grant.inc
--echo #
--echo # MDEV-21973 Bind REPLICATION {MASTER|SLAVE} ADMIN to gtid_* GLOBAL-only system variables
--echo #
--let var = gtid_strict_mode
--let grant = REPLICATION SLAVE ADMIN
--let value = 1
--source suite/sys_vars/inc/sysvar_global_grant.inc
......@@ -485,6 +485,9 @@ constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_RPL_SEMI_SYNC_MASTER_WAIT_POINT
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_MASTER_VERIFY_CHECKSUM=
REPL_MASTER_ADMIN_ACL | SUPER_ACL;
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_BINLOG_STATE=
REPL_MASTER_ADMIN_ACL | SUPER_ACL;
/* Privileges for statements that are executed on the slave */
// Was SUPER_ACL prior to 10.5.2
......@@ -572,6 +575,17 @@ constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_RELAY_LOG=
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_SYNC_RELAY_LOG_INFO=
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_CLEANUP_BATCH_SIZE=
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_IGNORE_DUPLICATES=
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_POS_AUTO_ENGINES=
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_SLAVE_POS=
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_STRICT_MODE=
REPL_SLAVE_ADMIN_ACL | SUPER_ACL;
/* Privileges for federated database related statements */
// Was SUPER_ACL prior to 10.5.2
......
......@@ -1982,7 +1982,9 @@ static Sys_var_gtid_slave_pos Sys_gtid_slave_pos(
GLOBAL_VAR(opt_gtid_slave_pos_dummy), NO_CMD_LINE);
static Sys_var_mybool Sys_gtid_strict_mode(
static Sys_var_on_access_global<Sys_var_mybool,
PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_STRICT_MODE>
Sys_gtid_strict_mode(
"gtid_strict_mode",
"Enforce strict seq_no ordering of events in the binary log. Slave "
"stops with an error if it encounters an event that would cause it to "
......@@ -2126,7 +2128,9 @@ Sys_var_last_gtid::session_value_ptr(THD *thd, const LEX_CSTRING *base)
}
static Sys_var_uint Sys_gtid_cleanup_batch_size(
static Sys_var_on_access_global<Sys_var_uint,
PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_CLEANUP_BATCH_SIZE>
Sys_gtid_cleanup_batch_size(
"gtid_cleanup_batch_size",
"Normally does not need tuning. How many old rows must accumulate in "
"the mysql.gtid_slave_pos table before a background job will be run to "
......@@ -2364,7 +2368,9 @@ fix_gtid_ignore_duplicates(sys_var *self, THD *thd, enum_var_type type)
}
static Sys_var_mybool Sys_gtid_ignore_duplicates(
static Sys_var_on_access_global<Sys_var_mybool,
PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_IGNORE_DUPLICATES>
Sys_gtid_ignore_duplicates(
"gtid_ignore_duplicates",
"When set, different master connections in multi-source replication are "
"allowed to receive and process event groups with the same GTID (when "
......@@ -4209,7 +4215,9 @@ check_gtid_pos_auto_engines(sys_var *self, THD *thd, set_var *var)
}
static Sys_var_pluginlist Sys_gtid_pos_auto_engines(
static Sys_var_on_access_global<Sys_var_pluginlist,
PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_POS_AUTO_ENGINES>
Sys_gtid_pos_auto_engines(
"gtid_pos_auto_engines",
"List of engines for which to automatically create a "
"mysql.gtid_slave_pos_ENGINE table, if a transaction using that engine "
......
......@@ -2531,6 +2531,10 @@ public:
uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base);
uchar *default_value_ptr(THD *thd)
{ return 0; }
bool on_check_access_global(THD *thd) const
{
return check_global_access(thd, PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_SLAVE_POS);
}
};
......@@ -2573,6 +2577,11 @@ public:
uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base);
uchar *default_value_ptr(THD *thd)
{ return 0; }
bool on_check_access_global(THD *thd) const
{
return
check_global_access(thd, PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_BINLOG_STATE);
}
};
......
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