mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
MDEV-25515 User Account Host Names using CIDR notation
CREATE USER u@'192.168.0.0/24'; -- same as '192.168.0.0/255.255.255.0' CIDR is an input spelling only, normalised to the netmask form while parsing. A malformed mask is now rejected instead of stored, and one already in the privilege tables is skipped at load with a warning instead of being honoured. Nothing rejected these before, and they are not merely useless: a non-contiguous mask such as 10.0.0.0/255.0.255.0 matches the scattered set 10.*0.*. Skipping rather than erroring keeps such a row droppable and renamable, except for a literal CIDR host stored by an older version (for example 10.0.0.0/24): the parser converts that name, so it can no longer be named and must be removed with a direct DELETE from the privilege tables. New error ER_INVALID_HOST_NETMASK, ER_ACL_ENTRY_IGNORED_BAD_HOST_MASK
This commit is contained in:
committed by
mariadb-PranavTiwari
parent
327437ade1
commit
f6d172c03b
319
mysql-test/main/host_cidr.result
Normal file
319
mysql-test/main/host_cidr.result
Normal file
@@ -0,0 +1,319 @@
|
||||
#
|
||||
# MDEV-25515 User Account Host Names using CIDR notation
|
||||
#
|
||||
call mtr.add_suppression("ignored, the host is not a valid ip/netmask");
|
||||
# CIDR is stored in the netmask form
|
||||
CREATE USER c1@'127.0.0.0/8' IDENTIFIED BY 'pw';
|
||||
CREATE USER c2@'127.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
CREATE USER c3@'127.0.0.1/32' IDENTIFIED BY 'pw';
|
||||
CREATE USER c4@'127.0.0.0/31' IDENTIFIED BY 'pw';
|
||||
CREATE USER c5@'0.0.0.0/1' IDENTIFIED BY 'pw';
|
||||
CREATE USER n1@'127.0.0.0/255.0.0.0' IDENTIFIED BY 'pw';
|
||||
CREATE USER n2@'127.0.0.0/255.255.255.0' IDENTIFIED BY 'pw';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User LIKE 'c_' OR User LIKE 'n_'
|
||||
ORDER BY User;
|
||||
User Host
|
||||
c1 127.0.0.0/255.0.0.0
|
||||
c2 127.0.0.0/255.255.255.0
|
||||
c3 127.0.0.1/255.255.255.255
|
||||
c4 127.0.0.0/255.255.255.254
|
||||
c5 0.0.0.0/128.0.0.0
|
||||
n1 127.0.0.0/255.0.0.0
|
||||
n2 127.0.0.0/255.255.255.0
|
||||
SHOW CREATE USER c1@'127.0.0.0/8';
|
||||
CREATE USER for c1@127.0.0.0/255.0.0.0
|
||||
CREATE USER `c1`@`127.0.0.0/255.0.0.0` IDENTIFIED BY PASSWORD '*D821809F681A40A6E379B50D0463EFAE20BDD122'
|
||||
SHOW GRANTS FOR c2@'127.0.0.0/24';
|
||||
Grants for c2@127.0.0.0/255.255.255.0
|
||||
GRANT USAGE ON *.* TO `c2`@`127.0.0.0/255.255.255.0` IDENTIFIED BY PASSWORD '*D821809F681A40A6E379B50D0463EFAE20BDD122'
|
||||
# Both spellings are the same account
|
||||
CREATE USER dup@'127.0.0.0/8' IDENTIFIED BY 'pw';
|
||||
CREATE USER dup@'127.0.0.0/255.0.0.0' IDENTIFIED BY 'other';
|
||||
ERROR HY000: Operation CREATE USER failed for 'dup'@'127.0.0.0/255.0.0.0'
|
||||
CREATE USER IF NOT EXISTS dup@'127.0.0.0/255.0.0.0' IDENTIFIED BY 'other';
|
||||
Warnings:
|
||||
Note 1973 Can't create user 'dup'@'127.0.0.0/255.0.0.0'; it already exists
|
||||
CREATE USER dup@'127.000.0.0/8' IDENTIFIED BY 'other';
|
||||
ERROR HY000: Operation CREATE USER failed for 'dup'@'127.0.0.0/255.0.0.0'
|
||||
CREATE USER dup@'127.0.0.0/+8' IDENTIFIED BY 'other';
|
||||
ERROR HY000: Operation CREATE USER failed for 'dup'@'127.0.0.0/255.0.0.0'
|
||||
CREATE USER dup@'127.0.0.0/ 8' IDENTIFIED BY 'other';
|
||||
ERROR HY000: Operation CREATE USER failed for 'dup'@'127.0.0.0/255.0.0.0'
|
||||
CREATE USER dup@'127.0.0.0/255.000.0.0' IDENTIFIED BY 'other';
|
||||
ERROR HY000: Operation CREATE USER failed for 'dup'@'127.0.0.0/255.0.0.0'
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User='dup';
|
||||
User Host
|
||||
dup 127.0.0.0/255.0.0.0
|
||||
DROP USER dup@'127.0.0.0/8';
|
||||
# Matching is unchanged
|
||||
connect con1,127.0.0.1,c1,pw,,$MASTER_MYPORT,;
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
CURRENT_USER()
|
||||
c1@127.0.0.0/255.0.0.0
|
||||
disconnect con1;
|
||||
connection default;
|
||||
connect con1,127.0.0.1,c2,pw,,$MASTER_MYPORT,;
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
CURRENT_USER()
|
||||
c2@127.0.0.0/255.255.255.0
|
||||
disconnect con1;
|
||||
connection default;
|
||||
connect con1,127.0.0.1,c3,pw,,$MASTER_MYPORT,;
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
CURRENT_USER()
|
||||
c3@127.0.0.1/255.255.255.255
|
||||
disconnect con1;
|
||||
connection default;
|
||||
connect con1,127.0.0.1,c4,pw,,$MASTER_MYPORT,;
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
CURRENT_USER()
|
||||
c4@127.0.0.0/255.255.255.254
|
||||
disconnect con1;
|
||||
connection default;
|
||||
connect con1,127.0.0.1,c5,pw,,$MASTER_MYPORT,;
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
CURRENT_USER()
|
||||
c5@0.0.0.0/128.0.0.0
|
||||
disconnect con1;
|
||||
connection default;
|
||||
connect con1,127.0.0.1,n1,pw,,$MASTER_MYPORT,;
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
CURRENT_USER()
|
||||
n1@127.0.0.0/255.0.0.0
|
||||
disconnect con1;
|
||||
connection default;
|
||||
CREATE USER z1@'127.0.0.0/32' IDENTIFIED BY 'pw';
|
||||
connect(127.0.0.1,z1,pw,test,MASTER_PORT,MASTER_SOCKET);
|
||||
connect con1,127.0.0.1,z1,pw,,$MASTER_MYPORT,;
|
||||
ERROR 28000: Access denied for user 'z1'@'localhost' (using password: YES)
|
||||
DROP USER z1@'127.0.0.0/32';
|
||||
# Either spelling resolves to the same row, in every privilege table
|
||||
CREATE DATABASE cidr_db;
|
||||
CREATE TABLE cidr_db.t (a INT);
|
||||
GRANT SELECT ON cidr_db.* TO c1@'127.0.0.0/255.0.0.0';
|
||||
SHOW GRANTS FOR c1@'127.0.0.0/8';
|
||||
Grants for c1@127.0.0.0/255.0.0.0
|
||||
GRANT USAGE ON *.* TO `c1`@`127.0.0.0/255.0.0.0` IDENTIFIED BY PASSWORD '*D821809F681A40A6E379B50D0463EFAE20BDD122'
|
||||
GRANT SELECT ON `cidr_db`.* TO `c1`@`127.0.0.0/255.0.0.0`
|
||||
GRANT INSERT ON cidr_db.* TO c1@'127.0.0.0/8';
|
||||
REVOKE SELECT ON cidr_db.* FROM c1@'127.0.0.0/8';
|
||||
SELECT User, Host FROM mysql.db WHERE User='c1';
|
||||
User Host
|
||||
c1 127.0.0.0/255.0.0.0
|
||||
GRANT SELECT ON cidr_db.t TO c1@'127.0.0.0/8';
|
||||
SELECT User, Host FROM mysql.tables_priv WHERE User='c1';
|
||||
User Host
|
||||
c1 127.0.0.0/255.0.0.0
|
||||
REVOKE SELECT ON cidr_db.t FROM c1@'127.0.0.0/255.0.0.0';
|
||||
SET PASSWORD FOR c1@'127.0.0.0/8' = PASSWORD('pw2');
|
||||
ALTER USER c1@'127.0.0.0/255.0.0.0' IDENTIFIED BY 'pw';
|
||||
RENAME USER c1@'127.0.0.0/8' TO c1@'127.0.0.0/16';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User='c1';
|
||||
User Host
|
||||
c1 127.0.0.0/255.255.0.0
|
||||
SELECT User, Host FROM mysql.db WHERE User='c1';
|
||||
User Host
|
||||
c1 127.0.0.0/255.255.0.0
|
||||
RENAME USER c1@'127.0.0.0/255.255.0.0' TO c1@'127.0.0.0/8';
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM c1@'127.0.0.0/255.0.0.0';
|
||||
SHOW GRANTS FOR c1@'127.0.0.0/8';
|
||||
Grants for c1@127.0.0.0/255.0.0.0
|
||||
GRANT USAGE ON *.* TO `c1`@`127.0.0.0/255.0.0.0` IDENTIFIED BY PASSWORD '*D821809F681A40A6E379B50D0463EFAE20BDD122'
|
||||
DROP TABLE cidr_db.t;
|
||||
DROP DATABASE cidr_db;
|
||||
# GRANT normalises the host of an account it auto-creates
|
||||
CREATE TABLE test.t (a INT);
|
||||
CREATE PROCEDURE test.p1() SELECT 1;
|
||||
CREATE ROLE cidr_role;
|
||||
GRANT SELECT ON test.* TO g1@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
GRANT SELECT ON test.t TO g2@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
GRANT EXECUTE ON PROCEDURE test.p1 TO g3@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
GRANT cidr_role TO g4@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
GRANT PROXY ON ''@'%' TO g5@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User LIKE 'g_' ORDER BY User;
|
||||
User Host
|
||||
g1 10.0.0.0/255.255.255.0
|
||||
g2 10.0.0.0/255.255.255.0
|
||||
g3 10.0.0.0/255.255.255.0
|
||||
g4 10.0.0.0/255.255.255.0
|
||||
g5 10.0.0.0/255.255.255.0
|
||||
SELECT User, Host FROM mysql.db WHERE User='g1';
|
||||
User Host
|
||||
g1 10.0.0.0/255.255.255.0
|
||||
SELECT User, Host FROM mysql.tables_priv WHERE User='g2';
|
||||
User Host
|
||||
g2 10.0.0.0/255.255.255.0
|
||||
SELECT User, Host FROM mysql.procs_priv WHERE User='g3';
|
||||
User Host
|
||||
g3 10.0.0.0/255.255.255.0
|
||||
SELECT User, Host FROM mysql.roles_mapping WHERE User='g4';
|
||||
User Host
|
||||
g4 10.0.0.0/255.255.255.0
|
||||
SELECT User, Host FROM mysql.proxies_priv WHERE User='g5';
|
||||
User Host
|
||||
g5 10.0.0.0/255.255.255.0
|
||||
DROP USER g1@'10.0.0.0/255.255.255.0', g2@'10.0.0.0/255.255.255.0',
|
||||
g3@'10.0.0.0/255.255.255.0', g4@'10.0.0.0/255.255.255.0',
|
||||
g5@'10.0.0.0/255.255.255.0';
|
||||
DROP ROLE cidr_role;
|
||||
DROP PROCEDURE test.p1;
|
||||
DROP TABLE test.t;
|
||||
# DEFINER reaches the same grammar rule
|
||||
CREATE USER def@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
GRANT ALL ON test.* TO def@'10.0.0.0/255.255.255.0';
|
||||
CREATE DEFINER=def@'10.0.0.0/24' VIEW test.v1 AS SELECT 1;
|
||||
CREATE DEFINER=def@'10.0.0.0/24' PROCEDURE test.p2() SELECT 1;
|
||||
SELECT definer FROM information_schema.views
|
||||
WHERE table_schema='test' AND table_name='v1';
|
||||
definer
|
||||
def@10.0.0.0/255.255.255.0
|
||||
SELECT definer FROM information_schema.routines
|
||||
WHERE routine_schema='test' AND routine_name='p2';
|
||||
definer
|
||||
def@10.0.0.0/255.255.255.0
|
||||
DROP VIEW test.v1;
|
||||
DROP PROCEDURE test.p2;
|
||||
DROP USER def@'10.0.0.0/255.255.255.0';
|
||||
# A host without '/' is not a masked host and is untouched
|
||||
CREATE USER v1@'%', v2@'10.0.0.%', v3@'127.0.0._', v4@'localhost',
|
||||
v5@'127.0.0.1', v6@'::1';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User LIKE 'v_' ORDER BY User;
|
||||
User Host
|
||||
v1 %
|
||||
v2 10.0.0.%
|
||||
v3 127.0.0._
|
||||
v4 localhost
|
||||
v5 127.0.0.1
|
||||
v6 ::1
|
||||
DROP USER v1@'%', v2@'10.0.0.%', v3@'127.0.0._', v4@'localhost',
|
||||
v5@'127.0.0.1', v6@'::1';
|
||||
# A malformed mask is rejected, quoting the host as it was written
|
||||
CREATE USER e01@'10.0.0.0/33';
|
||||
ERROR HY000: Invalid masked host '10.0.0.0/33' for user 'e01'
|
||||
CREATE USER e02@'10.0.0.0/0';
|
||||
ERROR HY000: Invalid masked host '10.0.0.0/0' for user 'e02'
|
||||
CREATE USER e03@'10.0.0.0/-1';
|
||||
ERROR HY000: Invalid masked host '10.0.0.0/-1' for user 'e03'
|
||||
CREATE USER e04@'10.0.0.0/0.0.0.0';
|
||||
ERROR HY000: Invalid masked host '10.0.0.0/0.0.0.0' for user 'e04'
|
||||
CREATE USER e05@'10.0.0.0/255.0.255.0';
|
||||
ERROR HY000: Invalid masked host '10.0.0.0/255.0.255.0' for user 'e05'
|
||||
CREATE USER e06@'10.0.0.0/255.255.0.255';
|
||||
ERROR HY000: Invalid masked host '10.0.0.0/255.255.0.255' for user 'e06'
|
||||
CREATE USER e07@'10.1.2.3/24';
|
||||
ERROR HY000: Invalid masked host '10.1.2.3/24' for user 'e07'
|
||||
CREATE USER e08@'10.1.2.3/255.255.255.0';
|
||||
ERROR HY000: Invalid masked host '10.1.2.3/255.255.255.0' for user 'e08'
|
||||
CREATE USER e09@'127.0.0.0/1';
|
||||
ERROR HY000: Invalid masked host '127.0.0.0/1' for user 'e09'
|
||||
CREATE USER e10@'2001:db8::/32';
|
||||
ERROR HY000: Invalid masked host '2001:db8::/32' for user 'e10'
|
||||
CREATE USER e11@'10.0.0.%/24';
|
||||
ERROR HY000: Invalid masked host '10.0.0.%/24' for user 'e11'
|
||||
CREATE USER e12@'10.0.0.0/abc';
|
||||
ERROR HY000: Invalid masked host '10.0.0.0/abc' for user 'e12'
|
||||
CREATE USER e13@'10.0.0.0/';
|
||||
ERROR HY000: Invalid masked host '10.0.0.0/' for user 'e13'
|
||||
CREATE USER e14@'10.0.0.0/24x';
|
||||
ERROR HY000: Invalid masked host '10.0.0.0/24x' for user 'e14'
|
||||
GRANT SELECT ON test.* TO e20@'10.0.0.0/33' IDENTIFIED BY 'pw';
|
||||
ERROR HY000: Invalid masked host '10.0.0.0/33' for user 'e20'
|
||||
GRANT SELECT ON test.* TO e21@'10.1.2.3/24' IDENTIFIED BY 'pw';
|
||||
ERROR HY000: Invalid masked host '10.1.2.3/24' for user 'e21'
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User LIKE 'e__';
|
||||
User Host
|
||||
ALTER USER e30@'10.0.0.0/33' IDENTIFIED BY 'pw';
|
||||
ERROR HY000: Operation ALTER USER failed for 'e30'@'10.0.0.0/33'
|
||||
REVOKE SELECT ON test.* FROM e30@'10.0.0.0/33';
|
||||
ERROR 42000: There is no such grant defined for user 'e30' on host '10.0.0.0/33'
|
||||
# RENAME USER validates the target only
|
||||
CREATE USER r1@'127.0.0.0/8' IDENTIFIED BY 'pw';
|
||||
RENAME USER r1@'127.0.0.0/8' TO r1@'10.1.2.3/24';
|
||||
ERROR HY000: Operation RENAME USER failed for 'r1'@'10.1.2.3/24'
|
||||
RENAME USER r1@'127.0.0.0/8' TO r1@'10.0.0.0/255.0.255.0';
|
||||
ERROR HY000: Operation RENAME USER failed for 'r1'@'10.0.0.0/255.0.255.0'
|
||||
SHOW WARNINGS;
|
||||
Level Code Message
|
||||
Warning 4274 Invalid masked host '10.0.0.0/255.0.255.0' for user 'r1'
|
||||
Error 1396 Operation RENAME USER failed for 'r1'@'10.0.0.0/255.0.255.0'
|
||||
RENAME USER r1@'127.0.0.0/8' TO r1@'10.0.0.0/16';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User='r1';
|
||||
User Host
|
||||
r1 10.0.0.0/255.255.0.0
|
||||
DROP USER r1@'10.0.0.0/255.255.0.0';
|
||||
# acl_load() skips a stored row whose mask it cannot honour
|
||||
CREATE USER leg@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
UPDATE mysql.global_priv SET Host='10.0.0.0/255.0.255.0' WHERE User='leg';
|
||||
FLUSH PRIVILEGES;
|
||||
SHOW GRANTS FOR leg@'10.0.0.0/255.0.255.0';
|
||||
ERROR 42000: There is no such grant defined for user 'leg' on host '10.0.0.0/255.0.255.0'
|
||||
RENAME USER leg@'10.0.0.0/255.0.255.0' TO leg@'10.0.0.0/16';
|
||||
FLUSH PRIVILEGES;
|
||||
SHOW GRANTS FOR leg@'10.0.0.0/255.255.0.0';
|
||||
Grants for leg@10.0.0.0/255.255.0.0
|
||||
GRANT USAGE ON *.* TO `leg`@`10.0.0.0/255.255.0.0` IDENTIFIED BY PASSWORD '*D821809F681A40A6E379B50D0463EFAE20BDD122'
|
||||
DROP USER leg@'10.0.0.0/255.255.0.0';
|
||||
CREATE USER leg2@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
UPDATE mysql.global_priv SET Host='10.1.2.3/255.255.255.0' WHERE User='leg2';
|
||||
FLUSH PRIVILEGES;
|
||||
DROP USER leg2@'10.1.2.3/255.255.255.0';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User='leg2';
|
||||
User Host
|
||||
CREATE USER leg3@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
UPDATE mysql.global_priv SET Host='10.0.0.0/24' WHERE User='leg3';
|
||||
FLUSH PRIVILEGES;
|
||||
SHOW GRANTS FOR leg3@'10.0.0.0/24';
|
||||
ERROR 42000: There is no such grant defined for user 'leg3' on host '10.0.0.0/255.255.255.0'
|
||||
DROP USER leg3@'10.0.0.0/24';
|
||||
ERROR HY000: Operation DROP USER failed for 'leg3'@'10.0.0.0/255.255.255.0'
|
||||
DELETE FROM mysql.global_priv WHERE User='leg3';
|
||||
FLUSH PRIVILEGES;
|
||||
# ... in tables_priv and procs_priv too
|
||||
CREATE DATABASE legdb;
|
||||
CREATE TABLE legdb.t (a INT);
|
||||
CREATE PROCEDURE legdb.p() SELECT 1;
|
||||
CREATE USER legt@'%' IDENTIFIED BY 'pw';
|
||||
GRANT SELECT ON legdb.t TO legt@'%';
|
||||
GRANT EXECUTE ON PROCEDURE legdb.p TO legt@'%';
|
||||
connect con1,127.0.0.1,legt,pw,,$MASTER_MYPORT,;
|
||||
connection con1;
|
||||
SELECT * FROM legdb.t;
|
||||
a
|
||||
CALL legdb.p();
|
||||
1
|
||||
1
|
||||
disconnect con1;
|
||||
connection default;
|
||||
UPDATE mysql.tables_priv SET Host='127.0.0.0/255.0.255.0' WHERE User='legt';
|
||||
UPDATE mysql.procs_priv SET Host='127.0.0.0/255.0.255.0' WHERE User='legt';
|
||||
FLUSH PRIVILEGES;
|
||||
connect con1,127.0.0.1,legt,pw,,$MASTER_MYPORT,;
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
CURRENT_USER()
|
||||
legt@%
|
||||
SELECT * FROM legdb.t;
|
||||
ERROR 42000: SELECT command denied to user 'legt'@'localhost' for table `legdb`.`t`
|
||||
CALL legdb.p();
|
||||
ERROR 42000: execute command denied to user 'legt'@'%' for routine 'legdb.p'
|
||||
disconnect con1;
|
||||
connection default;
|
||||
DELETE FROM mysql.tables_priv WHERE User='legt';
|
||||
DELETE FROM mysql.procs_priv WHERE User='legt';
|
||||
DROP USER legt@'%';
|
||||
DROP PROCEDURE legdb.p;
|
||||
DROP TABLE legdb.t;
|
||||
DROP DATABASE legdb;
|
||||
DROP USER c1@'127.0.0.0/8', c2@'127.0.0.0/24', c3@'127.0.0.1/32',
|
||||
c4@'127.0.0.0/31', c5@'0.0.0.0/1',
|
||||
n1@'127.0.0.0/255.0.0.0', n2@'127.0.0.0/255.255.255.0';
|
||||
FLUSH PRIVILEGES;
|
||||
#
|
||||
# End of MDEV-25515 tests
|
||||
#
|
||||
259
mysql-test/main/host_cidr.test
Normal file
259
mysql-test/main/host_cidr.test
Normal file
@@ -0,0 +1,259 @@
|
||||
--source include/not_embedded.inc
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-25515 User Account Host Names using CIDR notation
|
||||
--echo #
|
||||
|
||||
call mtr.add_suppression("ignored, the host is not a valid ip/netmask");
|
||||
|
||||
--echo # CIDR is stored in the netmask form
|
||||
CREATE USER c1@'127.0.0.0/8' IDENTIFIED BY 'pw';
|
||||
CREATE USER c2@'127.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
CREATE USER c3@'127.0.0.1/32' IDENTIFIED BY 'pw';
|
||||
CREATE USER c4@'127.0.0.0/31' IDENTIFIED BY 'pw';
|
||||
CREATE USER c5@'0.0.0.0/1' IDENTIFIED BY 'pw';
|
||||
CREATE USER n1@'127.0.0.0/255.0.0.0' IDENTIFIED BY 'pw';
|
||||
CREATE USER n2@'127.0.0.0/255.255.255.0' IDENTIFIED BY 'pw';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User LIKE 'c_' OR User LIKE 'n_'
|
||||
ORDER BY User;
|
||||
SHOW CREATE USER c1@'127.0.0.0/8';
|
||||
SHOW GRANTS FOR c2@'127.0.0.0/24';
|
||||
|
||||
--echo # Both spellings are the same account
|
||||
CREATE USER dup@'127.0.0.0/8' IDENTIFIED BY 'pw';
|
||||
--error ER_CANNOT_USER
|
||||
CREATE USER dup@'127.0.0.0/255.0.0.0' IDENTIFIED BY 'other';
|
||||
CREATE USER IF NOT EXISTS dup@'127.0.0.0/255.0.0.0' IDENTIFIED BY 'other';
|
||||
|
||||
--error ER_CANNOT_USER
|
||||
CREATE USER dup@'127.000.0.0/8' IDENTIFIED BY 'other';
|
||||
--error ER_CANNOT_USER
|
||||
CREATE USER dup@'127.0.0.0/+8' IDENTIFIED BY 'other';
|
||||
--error ER_CANNOT_USER
|
||||
CREATE USER dup@'127.0.0.0/ 8' IDENTIFIED BY 'other';
|
||||
--error ER_CANNOT_USER
|
||||
CREATE USER dup@'127.0.0.0/255.000.0.0' IDENTIFIED BY 'other';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User='dup';
|
||||
DROP USER dup@'127.0.0.0/8';
|
||||
|
||||
--echo # Matching is unchanged
|
||||
connect (con1,127.0.0.1,c1,pw,,$MASTER_MYPORT,);
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
disconnect con1;
|
||||
connection default;
|
||||
connect (con1,127.0.0.1,c2,pw,,$MASTER_MYPORT,);
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
disconnect con1;
|
||||
connection default;
|
||||
connect (con1,127.0.0.1,c3,pw,,$MASTER_MYPORT,);
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
disconnect con1;
|
||||
connection default;
|
||||
connect (con1,127.0.0.1,c4,pw,,$MASTER_MYPORT,);
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
disconnect con1;
|
||||
connection default;
|
||||
connect (con1,127.0.0.1,c5,pw,,$MASTER_MYPORT,);
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
disconnect con1;
|
||||
connection default;
|
||||
connect (con1,127.0.0.1,n1,pw,,$MASTER_MYPORT,);
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
disconnect con1;
|
||||
connection default;
|
||||
|
||||
CREATE USER z1@'127.0.0.0/32' IDENTIFIED BY 'pw';
|
||||
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||
--error ER_ACCESS_DENIED_ERROR
|
||||
connect (con1,127.0.0.1,z1,pw,,$MASTER_MYPORT,);
|
||||
DROP USER z1@'127.0.0.0/32';
|
||||
|
||||
|
||||
--echo # Either spelling resolves to the same row, in every privilege table
|
||||
CREATE DATABASE cidr_db;
|
||||
CREATE TABLE cidr_db.t (a INT);
|
||||
GRANT SELECT ON cidr_db.* TO c1@'127.0.0.0/255.0.0.0';
|
||||
SHOW GRANTS FOR c1@'127.0.0.0/8';
|
||||
GRANT INSERT ON cidr_db.* TO c1@'127.0.0.0/8';
|
||||
REVOKE SELECT ON cidr_db.* FROM c1@'127.0.0.0/8';
|
||||
SELECT User, Host FROM mysql.db WHERE User='c1';
|
||||
GRANT SELECT ON cidr_db.t TO c1@'127.0.0.0/8';
|
||||
SELECT User, Host FROM mysql.tables_priv WHERE User='c1';
|
||||
REVOKE SELECT ON cidr_db.t FROM c1@'127.0.0.0/255.0.0.0';
|
||||
SET PASSWORD FOR c1@'127.0.0.0/8' = PASSWORD('pw2');
|
||||
ALTER USER c1@'127.0.0.0/255.0.0.0' IDENTIFIED BY 'pw';
|
||||
RENAME USER c1@'127.0.0.0/8' TO c1@'127.0.0.0/16';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User='c1';
|
||||
SELECT User, Host FROM mysql.db WHERE User='c1';
|
||||
RENAME USER c1@'127.0.0.0/255.255.0.0' TO c1@'127.0.0.0/8';
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM c1@'127.0.0.0/255.0.0.0';
|
||||
SHOW GRANTS FOR c1@'127.0.0.0/8';
|
||||
DROP TABLE cidr_db.t;
|
||||
DROP DATABASE cidr_db;
|
||||
|
||||
--echo # GRANT normalises the host of an account it auto-creates
|
||||
CREATE TABLE test.t (a INT);
|
||||
CREATE PROCEDURE test.p1() SELECT 1;
|
||||
CREATE ROLE cidr_role;
|
||||
GRANT SELECT ON test.* TO g1@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
GRANT SELECT ON test.t TO g2@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
GRANT EXECUTE ON PROCEDURE test.p1 TO g3@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
GRANT cidr_role TO g4@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
GRANT PROXY ON ''@'%' TO g5@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User LIKE 'g_' ORDER BY User;
|
||||
SELECT User, Host FROM mysql.db WHERE User='g1';
|
||||
SELECT User, Host FROM mysql.tables_priv WHERE User='g2';
|
||||
SELECT User, Host FROM mysql.procs_priv WHERE User='g3';
|
||||
SELECT User, Host FROM mysql.roles_mapping WHERE User='g4';
|
||||
SELECT User, Host FROM mysql.proxies_priv WHERE User='g5';
|
||||
DROP USER g1@'10.0.0.0/255.255.255.0', g2@'10.0.0.0/255.255.255.0',
|
||||
g3@'10.0.0.0/255.255.255.0', g4@'10.0.0.0/255.255.255.0',
|
||||
g5@'10.0.0.0/255.255.255.0';
|
||||
DROP ROLE cidr_role;
|
||||
DROP PROCEDURE test.p1;
|
||||
DROP TABLE test.t;
|
||||
|
||||
--echo # DEFINER reaches the same grammar rule
|
||||
CREATE USER def@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
GRANT ALL ON test.* TO def@'10.0.0.0/255.255.255.0';
|
||||
CREATE DEFINER=def@'10.0.0.0/24' VIEW test.v1 AS SELECT 1;
|
||||
CREATE DEFINER=def@'10.0.0.0/24' PROCEDURE test.p2() SELECT 1;
|
||||
SELECT definer FROM information_schema.views
|
||||
WHERE table_schema='test' AND table_name='v1';
|
||||
SELECT definer FROM information_schema.routines
|
||||
WHERE routine_schema='test' AND routine_name='p2';
|
||||
DROP VIEW test.v1;
|
||||
DROP PROCEDURE test.p2;
|
||||
DROP USER def@'10.0.0.0/255.255.255.0';
|
||||
|
||||
--echo # A host without '/' is not a masked host and is untouched
|
||||
CREATE USER v1@'%', v2@'10.0.0.%', v3@'127.0.0._', v4@'localhost',
|
||||
v5@'127.0.0.1', v6@'::1';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User LIKE 'v_' ORDER BY User;
|
||||
DROP USER v1@'%', v2@'10.0.0.%', v3@'127.0.0._', v4@'localhost',
|
||||
v5@'127.0.0.1', v6@'::1';
|
||||
|
||||
--echo # A malformed mask is rejected, quoting the host as it was written
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e01@'10.0.0.0/33';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e02@'10.0.0.0/0';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e03@'10.0.0.0/-1';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e04@'10.0.0.0/0.0.0.0';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e05@'10.0.0.0/255.0.255.0';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e06@'10.0.0.0/255.255.0.255';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e07@'10.1.2.3/24';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e08@'10.1.2.3/255.255.255.0';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e09@'127.0.0.0/1';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e10@'2001:db8::/32';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e11@'10.0.0.%/24';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e12@'10.0.0.0/abc';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e13@'10.0.0.0/';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
CREATE USER e14@'10.0.0.0/24x';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
GRANT SELECT ON test.* TO e20@'10.0.0.0/33' IDENTIFIED BY 'pw';
|
||||
--error ER_INVALID_HOST_NETMASK
|
||||
GRANT SELECT ON test.* TO e21@'10.1.2.3/24' IDENTIFIED BY 'pw';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User LIKE 'e__';
|
||||
|
||||
--error ER_CANNOT_USER
|
||||
ALTER USER e30@'10.0.0.0/33' IDENTIFIED BY 'pw';
|
||||
--error ER_NONEXISTING_GRANT
|
||||
REVOKE SELECT ON test.* FROM e30@'10.0.0.0/33';
|
||||
|
||||
--echo # RENAME USER validates the target only
|
||||
CREATE USER r1@'127.0.0.0/8' IDENTIFIED BY 'pw';
|
||||
--error ER_CANNOT_USER
|
||||
RENAME USER r1@'127.0.0.0/8' TO r1@'10.1.2.3/24';
|
||||
--error ER_CANNOT_USER
|
||||
RENAME USER r1@'127.0.0.0/8' TO r1@'10.0.0.0/255.0.255.0';
|
||||
SHOW WARNINGS;
|
||||
RENAME USER r1@'127.0.0.0/8' TO r1@'10.0.0.0/16';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User='r1';
|
||||
DROP USER r1@'10.0.0.0/255.255.0.0';
|
||||
|
||||
--echo # acl_load() skips a stored row whose mask it cannot honour
|
||||
CREATE USER leg@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
UPDATE mysql.global_priv SET Host='10.0.0.0/255.0.255.0' WHERE User='leg';
|
||||
FLUSH PRIVILEGES;
|
||||
--error ER_NONEXISTING_GRANT
|
||||
SHOW GRANTS FOR leg@'10.0.0.0/255.0.255.0';
|
||||
RENAME USER leg@'10.0.0.0/255.0.255.0' TO leg@'10.0.0.0/16';
|
||||
FLUSH PRIVILEGES;
|
||||
SHOW GRANTS FOR leg@'10.0.0.0/255.255.0.0';
|
||||
DROP USER leg@'10.0.0.0/255.255.0.0';
|
||||
|
||||
CREATE USER leg2@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
UPDATE mysql.global_priv SET Host='10.1.2.3/255.255.255.0' WHERE User='leg2';
|
||||
FLUSH PRIVILEGES;
|
||||
DROP USER leg2@'10.1.2.3/255.255.255.0';
|
||||
SELECT User, Host FROM mysql.global_priv WHERE User='leg2';
|
||||
|
||||
CREATE USER leg3@'10.0.0.0/24' IDENTIFIED BY 'pw';
|
||||
UPDATE mysql.global_priv SET Host='10.0.0.0/24' WHERE User='leg3';
|
||||
FLUSH PRIVILEGES;
|
||||
--error ER_NONEXISTING_GRANT
|
||||
SHOW GRANTS FOR leg3@'10.0.0.0/24';
|
||||
--error ER_CANNOT_USER
|
||||
DROP USER leg3@'10.0.0.0/24';
|
||||
DELETE FROM mysql.global_priv WHERE User='leg3';
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
--echo # ... in tables_priv and procs_priv too
|
||||
CREATE DATABASE legdb;
|
||||
CREATE TABLE legdb.t (a INT);
|
||||
CREATE PROCEDURE legdb.p() SELECT 1;
|
||||
CREATE USER legt@'%' IDENTIFIED BY 'pw';
|
||||
GRANT SELECT ON legdb.t TO legt@'%';
|
||||
GRANT EXECUTE ON PROCEDURE legdb.p TO legt@'%';
|
||||
connect (con1,127.0.0.1,legt,pw,,$MASTER_MYPORT,);
|
||||
connection con1;
|
||||
SELECT * FROM legdb.t;
|
||||
CALL legdb.p();
|
||||
disconnect con1;
|
||||
connection default;
|
||||
UPDATE mysql.tables_priv SET Host='127.0.0.0/255.0.255.0' WHERE User='legt';
|
||||
UPDATE mysql.procs_priv SET Host='127.0.0.0/255.0.255.0' WHERE User='legt';
|
||||
FLUSH PRIVILEGES;
|
||||
connect (con1,127.0.0.1,legt,pw,,$MASTER_MYPORT,);
|
||||
connection con1;
|
||||
SELECT CURRENT_USER();
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
SELECT * FROM legdb.t;
|
||||
--error ER_PROCACCESS_DENIED_ERROR
|
||||
CALL legdb.p();
|
||||
disconnect con1;
|
||||
connection default;
|
||||
DELETE FROM mysql.tables_priv WHERE User='legt';
|
||||
DELETE FROM mysql.procs_priv WHERE User='legt';
|
||||
DROP USER legt@'%';
|
||||
DROP PROCEDURE legdb.p;
|
||||
DROP TABLE legdb.t;
|
||||
DROP DATABASE legdb;
|
||||
|
||||
DROP USER c1@'127.0.0.0/8', c2@'127.0.0.0/24', c3@'127.0.0.1/32',
|
||||
c4@'127.0.0.0/31', c5@'0.0.0.0/1',
|
||||
n1@'127.0.0.0/255.0.0.0', n2@'127.0.0.0/255.255.255.0';
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
--echo #
|
||||
--echo # End of MDEV-25515 tests
|
||||
--echo #
|
||||
@@ -12423,3 +12423,7 @@ ER_RESULT_CUT_BY_LIMIT
|
||||
eng "Result was cut by %s) because of %s limit"
|
||||
ER_CUT_VALUES_WHILE_PROCESSING
|
||||
eng "Some values were cut while processing %s). Increase %s if you want to avoid the cut"
|
||||
ER_INVALID_HOST_NETMASK
|
||||
eng "Invalid masked host '%s' for user '%s'"
|
||||
ER_ACL_ENTRY_IGNORED_BAD_HOST_MASK
|
||||
eng "'%s' entry '%s' ignored, the host is not a valid ip/netmask"
|
||||
|
||||
181
sql/sql_acl.cc
181
sql/sql_acl.cc
@@ -339,6 +339,7 @@ ulong role_global_merges= 0, role_db_merges= 0, role_table_merges= 0,
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
static bool ignore_max_password_errors(const ACL_USER *acl_user);
|
||||
static void update_hostname(acl_host_and_ip *host, const char *hostname);
|
||||
static bool valid_host_mask(const char *hostname);
|
||||
static bool show_proxy_grants (THD *, const char *, const char *,
|
||||
char *, size_t);
|
||||
static bool show_role_grants(THD *, const char *,
|
||||
@@ -443,6 +444,17 @@ public:
|
||||
safe_str(host.hostname));
|
||||
return TRUE;
|
||||
}
|
||||
if (!valid_host_mask(host.hostname) ||
|
||||
!valid_host_mask(proxied_host.hostname))
|
||||
{
|
||||
char entry[2 * (USERNAME_LENGTH + HOSTNAME_LENGTH) + 4];
|
||||
my_snprintf(entry, sizeof(entry), "%s@%s %s@%s", proxied_user,
|
||||
safe_str(proxied_host.hostname), user,
|
||||
safe_str(host.hostname));
|
||||
sql_print_warning(ER_DEFAULT(ER_ACL_ENTRY_IGNORED_BAD_HOST_MASK),
|
||||
"proxies_priv", entry);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -3437,6 +3449,15 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
|
||||
host.host.hostname, host.db);
|
||||
continue;
|
||||
}
|
||||
if (!valid_host_mask(host.host.hostname))
|
||||
{
|
||||
char entry[HOSTNAME_LENGTH + NAME_LEN + 2];
|
||||
my_snprintf(entry, sizeof(entry), "%s|%s", host.host.hostname,
|
||||
safe_str(host.db));
|
||||
sql_print_warning(ER_DEFAULT(ER_ACL_ENTRY_IGNORED_BAD_HOST_MASK),
|
||||
"host", entry);
|
||||
continue;
|
||||
}
|
||||
#ifndef TO_BE_REMOVED
|
||||
if (host_table.num_fields() == 8)
|
||||
{ // Without grant
|
||||
@@ -3518,6 +3539,17 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skipped rows stay in the table, so DROP and RENAME USER still work */
|
||||
if (!valid_host_mask(user.host.hostname))
|
||||
{
|
||||
char entry[USERNAME_LENGTH + HOSTNAME_LENGTH + 2];
|
||||
my_snprintf(entry, sizeof(entry), "%s@%s", user.user.str,
|
||||
safe_str(user.host.hostname));
|
||||
sql_print_warning(ER_DEFAULT(ER_ACL_ENTRY_IGNORED_BAD_HOST_MASK),
|
||||
"user", entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (user_table.get_auth(thd, &acl_memroot, &user))
|
||||
continue;
|
||||
for (uint i= 0; i < user.nauth; i++)
|
||||
@@ -3592,6 +3624,15 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
|
||||
db.db, db.user, safe_str(db.host.hostname));
|
||||
continue;
|
||||
}
|
||||
if (!valid_host_mask(db.host.hostname))
|
||||
{
|
||||
char entry[NAME_LEN + USERNAME_LENGTH + HOSTNAME_LENGTH + 3];
|
||||
my_snprintf(entry, sizeof(entry), "%s %s@%s", db.db,
|
||||
db.user, safe_str(db.host.hostname));
|
||||
sql_print_warning(ER_DEFAULT(ER_ACL_ENTRY_IGNORED_BAD_HOST_MASK),
|
||||
"db", entry);
|
||||
continue;
|
||||
}
|
||||
db.access= access_t(fix_rights_for_db(db_table.get_access()));
|
||||
db.initial_access= db.access;
|
||||
db.sort=get_magic_sort("hdu", db.host.hostname, db.db, db.user);
|
||||
@@ -5407,6 +5448,101 @@ static const char *calc_ip(const char *ip, long *val, char end)
|
||||
return ip;
|
||||
}
|
||||
|
||||
/* Convert CIDR prefix length (1-32) to a 32-bit IPv4 subnet mask. */
|
||||
static const char *calc_cidr(const char *prefix_str, long *val)
|
||||
{
|
||||
uchar prefix;
|
||||
|
||||
if (!(prefix_str=str2int(prefix_str, INT16_MAX, 10, &prefix)) ||
|
||||
*prefix_str != '\0' || !prefix || prefix > 32)
|
||||
return 0;
|
||||
|
||||
*val= (long) (uint32) (0xFFFFFFFFU << (32 - prefix));
|
||||
return prefix_str;
|
||||
}
|
||||
|
||||
/*
|
||||
compare_hostname() tests (client_ip & ip_mask) == ip, so a zero or
|
||||
non-contiguous mask, or an ip with host bits set, can never match.
|
||||
*/
|
||||
static bool valid_masked_ip(long ip, long mask)
|
||||
{
|
||||
ulong inv, m= (ulong) (uint32) mask;
|
||||
|
||||
if (!m)
|
||||
return false; /* a mask of 0.0.0.0 */
|
||||
|
||||
inv= (~m) & 0xFFFFFFFFUL;
|
||||
if (inv & (inv + 1))
|
||||
return false; /* not contiguous */
|
||||
|
||||
return !(((ulong) (uint32) ip) & inv);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Rewrite a masked host into the canonical netmask spelling:
|
||||
|
||||
10.0.0.0/8 -> 10.0.0.0/255.0.0.0
|
||||
010.0.0.0/+8 -> 10.0.0.0/255.0.0.0
|
||||
10.0.0.0/255.0.0.0 -> unchanged, already canonical
|
||||
|
||||
Anything that is not a valid masked host is returned unchanged and no error
|
||||
is raised, so DROP USER and RENAME USER can still name a malformed host
|
||||
stored by a version that did not validate it.
|
||||
|
||||
The exception is a stored literal CIDR host such as 10.0.0.0/24: it is
|
||||
converted here, so it can no longer be named and has to be removed with a
|
||||
direct DELETE from the privilege tables.
|
||||
*/
|
||||
|
||||
LEX_CSTRING normalize_masked_host(THD *thd, const LEX_CSTRING &host)
|
||||
{
|
||||
long ip, mask;
|
||||
const char *p;
|
||||
char buf[32]; /* 255.255.255.255/255.255.255.255 and NUL */
|
||||
uint32 a, m;
|
||||
size_t len;
|
||||
|
||||
if (!host.str || !memchr(host.str, '/', host.length))
|
||||
return host;
|
||||
if (!(p= calc_ip(host.str, &ip, '/')))
|
||||
return host;
|
||||
if (!calc_ip(p + 1, &mask, '\0') && !calc_cidr(p + 1, &mask))
|
||||
return host;
|
||||
if (!valid_masked_ip(ip, mask))
|
||||
return host;
|
||||
|
||||
a= (uint32) ip;
|
||||
m= (uint32) mask;
|
||||
len= my_snprintf(buf, sizeof(buf), "%u.%u.%u.%u/%u.%u.%u.%u",
|
||||
a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
|
||||
m >> 24, (m >> 16) & 0xFF, (m >> 8) & 0xFF, m & 0xFF);
|
||||
|
||||
return thd->strmake_lex_cstring(buf, len);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Check that a host given in masked form is well formed:
|
||||
a.b.c.d/255.255.255.0
|
||||
|
||||
A CIDR prefix is rejected here on purpose: normalize_masked_host() has
|
||||
already rewritten every valid one, so a prefix reaching this point means
|
||||
the host never went through the parser.
|
||||
*/
|
||||
|
||||
static bool valid_host_mask(const char *hostname)
|
||||
{
|
||||
long ip, mask;
|
||||
const char *p;
|
||||
|
||||
if (!hostname || !strchr(hostname, '/'))
|
||||
return true; /* not a masked host */
|
||||
|
||||
return (p= calc_ip(hostname, &ip, '/')) &&
|
||||
calc_ip(p + 1, &mask, '\0') && valid_masked_ip(ip, mask);
|
||||
}
|
||||
|
||||
static void update_hostname(acl_host_and_ip *host, const char *hostname)
|
||||
{
|
||||
@@ -5666,6 +5802,14 @@ static int replace_user_table(THD *thd, const User_table &user_table,
|
||||
if (!combo->auth)
|
||||
combo->auth= &auth_no_password;
|
||||
|
||||
/* Only rows about to be created, so an older bad row stays droppable */
|
||||
if (!valid_host_mask(combo->host.str))
|
||||
{
|
||||
my_error(ER_INVALID_HOST_NETMASK, MYF(0), combo->host.str,
|
||||
combo->user.str);
|
||||
goto end;
|
||||
}
|
||||
|
||||
old_row_exists = 0;
|
||||
restore_record(table, s->default_values);
|
||||
user_table.set_host(combo->host.str, combo->host.length);
|
||||
@@ -9680,6 +9824,17 @@ static bool grant_load(THD *thd,
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid_host_mask(mem_check->host.hostname))
|
||||
{
|
||||
char entry[NAME_LEN + USERNAME_LENGTH + HOSTNAME_LENGTH + 3];
|
||||
my_snprintf(entry, sizeof(entry), "%s %s@%s", safe_str(mem_check->tname),
|
||||
mem_check->user, safe_str(mem_check->host.hostname));
|
||||
sql_print_warning(ER_DEFAULT(ER_ACL_ENTRY_IGNORED_BAD_HOST_MASK),
|
||||
"tables_priv", entry);
|
||||
delete mem_check;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! mem_check->ok())
|
||||
delete mem_check;
|
||||
else if (column_priv_insert(mem_check))
|
||||
@@ -9723,6 +9878,18 @@ static bool grant_load(THD *thd,
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid_host_mask(mem_check->host.hostname))
|
||||
{
|
||||
char entry[NAME_LEN + USERNAME_LENGTH + HOSTNAME_LENGTH + 3];
|
||||
my_snprintf(entry, sizeof(entry), "%s %s@%s",
|
||||
safe_str(mem_check->tname), mem_check->user,
|
||||
safe_str(mem_check->host.hostname));
|
||||
sql_print_warning(ER_DEFAULT(ER_ACL_ENTRY_IGNORED_BAD_HOST_MASK),
|
||||
"procs_priv", entry);
|
||||
delete mem_check;
|
||||
continue;
|
||||
}
|
||||
enum_sp_type type= (enum_sp_type)procs_priv.routine_type()->val_int();
|
||||
const Sp_handler *sph= Sp_handler::handler(type);
|
||||
if (!sph || !(hash= sph->get_priv_hash()))
|
||||
@@ -13332,6 +13499,18 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
|
||||
DBUG_ASSERT(!user_from->is_role());
|
||||
DBUG_ASSERT(!user_to->is_role());
|
||||
|
||||
/* Target only, so a bad host can be repaired by renaming it */
|
||||
if (!valid_host_mask(user_to->host.str))
|
||||
{
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_INVALID_HOST_NETMASK,
|
||||
ER_THD(thd, ER_INVALID_HOST_NETMASK),
|
||||
user_to->host.str, user_to->user.str);
|
||||
append_user(thd, &wrong_users, user_to);
|
||||
result= TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
Search all in-memory structures and grant tables
|
||||
for a mention of the new user name.
|
||||
@@ -14234,6 +14413,8 @@ access_t get_column_grant(THD *, GRANT_INFO *, const char *, const char *,
|
||||
{ return access_t(ALL_KNOWN_ACL); }
|
||||
int acl_check_setrole(THD *, const LEX_CSTRING &, access_t *) { return 0; }
|
||||
int acl_setrole(THD *, const LEX_CSTRING &, const access_t&) { return 0; }
|
||||
LEX_CSTRING normalize_masked_host(THD *, const LEX_CSTRING &host)
|
||||
{ return host; }
|
||||
#endif /*NO_EMBEDDED_ACCESS_CHECKS */
|
||||
|
||||
static int set_privs_on_login(THD *thd, const ACL_USER *acl_user)
|
||||
|
||||
@@ -148,6 +148,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list, bool handle_as_role);
|
||||
bool mysql_rename_user(THD *thd, List <LEX_USER> &list);
|
||||
int mysql_alter_user(THD *thd, List <LEX_USER> &list);
|
||||
bool mysql_revoke_all(THD *thd, List <LEX_USER> &list);
|
||||
LEX_CSTRING normalize_masked_host(THD *thd, const LEX_CSTRING &host);
|
||||
void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
|
||||
const char *db, const char *table);
|
||||
bool sp_revoke_privileges(THD *thd,
|
||||
|
||||
@@ -16824,7 +16824,12 @@ user_name:
|
||||
check_host_name(&$$->host))
|
||||
MYSQL_YYABORT;
|
||||
if ($$->host.str[0])
|
||||
{
|
||||
$$->host= thd->make_ident_casedn($$->host);
|
||||
$$->host= normalize_masked_host(thd, $$->host);
|
||||
if (unlikely(!$$->host.str))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
else
|
||||
$$->host= host_not_specified;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user