Skip to content

Commit 0a43df4

Browse files
committed
MDEV-14735 better matching order for grants
fixes MDEV-14732 mysql.db privileges evaluated on order of grants rather than hierarchically MDEV-8269 Correct fix for Bug #20181776 :- ACCESS CONTROL DOESN'T MATCH MOST SPECIFIC HOST WHEN IT CONTAINS WILDCARD reimplement the old ad hoc get_sort() function to use a wildcard pattern ordering logic that works correctly in may be all practical cases. get_sort() is renamed to catch merge errors at compilation time. moved to a separate included file, because of a long comment.
1 parent fd00c44 commit 0a43df4

File tree

4 files changed

+286
-55
lines changed

4 files changed

+286
-55
lines changed

mysql-test/main/grant5.result

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,28 @@ u6 Y mysql_old_password 78a302dd267f6044
102102
u7 Y mysql_old_password 78a302dd267f6044
103103
u8 Y nonexistent 78a302dd267f6044
104104
drop user u1@h, u2@h, u3@h, u4@h, u5@h, u6@h, u7@h, u8@h;
105+
create database mysqltest_1;
106+
create user twg@'%' identified by 'test';
107+
create table mysqltest_1.t1(id int);
108+
grant create, drop on `mysqltest_1%`.* to twg@'%';
109+
grant all privileges on `mysqltest_1`.* to twg@'%';
110+
connect conn1,localhost,twg,test,mysqltest_1;
111+
insert into t1 values(1);
112+
disconnect conn1;
113+
connection default;
114+
revoke all privileges, grant option from twg@'%';
115+
grant create, drop on `mysqlt%`.* to twg@'%';
116+
grant all privileges on `mysqlt%1`.* to twg@'%';
117+
connect conn1,localhost,twg,test,mysqltest_1;
118+
insert into t1 values(1);
119+
disconnect conn1;
120+
connection default;
121+
revoke all privileges, grant option from twg@'%';
122+
grant create, drop on `mysqlt%`.* to twg@'%';
123+
grant all privileges on `%mysqltest_1`.* to twg@'%';
124+
connect conn1,localhost,twg,test,mysqltest_1;
125+
insert into t1 values(1);
126+
disconnect conn1;
127+
connection default;
128+
drop database mysqltest_1;
129+
drop user twg@'%';

mysql-test/main/grant5.test

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,41 @@ select user,select_priv,plugin,authentication_string from mysql.user where user
8686

8787
# but they still can be dropped
8888
drop user u1@h, u2@h, u3@h, u4@h, u5@h, u6@h, u7@h, u8@h;
89+
90+
#
91+
# MDEV-14735 better matching order for grants
92+
# MDEV-14732 mysql.db privileges evaluated on order of grants rather than hierarchically
93+
# MDEV-8269 Correct fix for Bug #20181776 :- ACCESS CONTROL DOESN'T MATCH MOST SPECIFIC HOST WHEN IT CONTAINS WILDCARD
94+
#
95+
create database mysqltest_1;
96+
create user twg@'%' identified by 'test';
97+
create table mysqltest_1.t1(id int);
98+
99+
# MDEV-14732 test case
100+
grant create, drop on `mysqltest_1%`.* to twg@'%';
101+
grant all privileges on `mysqltest_1`.* to twg@'%';
102+
connect conn1,localhost,twg,test,mysqltest_1;
103+
insert into t1 values(1);
104+
disconnect conn1;
105+
connection default;
106+
107+
# prefix%suffix
108+
revoke all privileges, grant option from twg@'%';
109+
grant create, drop on `mysqlt%`.* to twg@'%';
110+
grant all privileges on `mysqlt%1`.* to twg@'%';
111+
connect conn1,localhost,twg,test,mysqltest_1;
112+
insert into t1 values(1);
113+
disconnect conn1;
114+
connection default;
115+
116+
# more specific can even have a shorter prefix
117+
revoke all privileges, grant option from twg@'%';
118+
grant create, drop on `mysqlt%`.* to twg@'%';
119+
grant all privileges on `%mysqltest_1`.* to twg@'%';
120+
connect conn1,localhost,twg,test,mysqltest_1;
121+
insert into t1 values(1);
122+
disconnect conn1;
123+
connection default;
124+
125+
drop database mysqltest_1;
126+
drop user twg@'%';

sql/sql_acl.cc

Lines changed: 18 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@
6262
bool mysql_user_table_is_in_short_password_format= false;
6363
bool using_global_priv_table= true;
6464

65+
// set that from field length in acl_load?
66+
const uint max_hostname_length= 60;
67+
const uint max_dbname_length= 64;
68+
69+
#include "sql_acl_getsort.ic"
70+
6571
static LEX_CSTRING native_password_plugin_name= {
6672
STRING_WITH_LEN("mysql_native_password")
6773
};
@@ -117,7 +123,7 @@ static bool compare_hostname(const acl_host_and_ip *, const char *, const char *
117123

118124
class ACL_ACCESS {
119125
public:
120-
ulong sort;
126+
ulonglong sort;
121127
ulong access;
122128
ACL_ACCESS()
123129
:sort(0), access(0)
@@ -284,7 +290,6 @@ ulong role_global_merges= 0, role_db_merges= 0, role_table_merges= 0,
284290

285291
#ifndef NO_EMBEDDED_ACCESS_CHECKS
286292
static void update_hostname(acl_host_and_ip *host, const char *hostname);
287-
static ulong get_sort(uint count,...);
288293
static bool show_proxy_grants (THD *, const char *, const char *,
289294
char *, size_t);
290295
static bool show_role_grants(THD *, const char *, const char *,
@@ -332,7 +337,8 @@ class ACL_PROXY_USER :public ACL_ACCESS
332337
(proxied_host_arg && *proxied_host_arg) ?
333338
proxied_host_arg : NULL);
334339
with_grant= with_grant_arg;
335-
sort= get_sort(4, host.hostname, user, proxied_host.hostname, proxied_user);
340+
sort= get_magic_sort("huhu", host.hostname, user, proxied_host.hostname,
341+
proxied_user);
336342
}
337343

338344
void init(MEM_ROOT *mem, const char *host_arg, const char *user_arg,
@@ -2344,7 +2350,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
23442350
}
23452351
host.access= host_table.get_access();
23462352
host.access= fix_rights_for_db(host.access);
2347-
host.sort= get_sort(2, host.host.hostname, host.db);
2353+
host.sort= get_magic_sort("hd", host.host.hostname, host.db);
23482354
if (check_no_resolve && hostname_requires_resolving(host.host.hostname))
23492355
{
23502356
sql_print_warning("'host' entry '%s|%s' "
@@ -2386,7 +2392,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
23862392

23872393
user.access= user_table.get_access();
23882394

2389-
user.sort= get_sort(2, user.host.hostname, user.user.str);
2395+
user.sort= get_magic_sort("hu", user.host.hostname, user.user.str);
23902396
user.hostname_length= safe_strlen(user.host.hostname);
23912397

23922398
my_init_dynamic_array(&user.role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0));
@@ -2505,7 +2511,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
25052511
db.db, db.user, safe_str(db.host.hostname));
25062512
}
25072513
}
2508-
db.sort=get_sort(3,db.host.hostname,db.db,db.user);
2514+
db.sort=get_magic_sort("hdu", db.host.hostname, db.db, db.user);
25092515
#ifndef TO_BE_REMOVED
25102516
if (db_table.num_fields() <= 9)
25112517
{ // Without grant
@@ -2753,49 +2759,6 @@ static ulong get_access(TABLE *form, uint fieldnr, uint *next_field)
27532759
}
27542760

27552761

2756-
/*
2757-
Return a number which, if sorted 'desc', puts strings in this order:
2758-
no wildcards
2759-
wildcards
2760-
empty string
2761-
*/
2762-
2763-
static ulong get_sort(uint count,...)
2764-
{
2765-
va_list args;
2766-
va_start(args,count);
2767-
ulong sort=0;
2768-
2769-
/* Should not use this function with more than 4 arguments for compare. */
2770-
DBUG_ASSERT(count <= 4);
2771-
2772-
while (count--)
2773-
{
2774-
char *start, *str= va_arg(args,char*);
2775-
uint chars= 0;
2776-
uint wild_pos= 0; /* first wildcard position */
2777-
2778-
if ((start= str))
2779-
{
2780-
for (; *str ; str++)
2781-
{
2782-
if (*str == wild_prefix && str[1])
2783-
str++;
2784-
else if (*str == wild_many || *str == wild_one)
2785-
{
2786-
wild_pos= (uint) (str - start) + 1;
2787-
break;
2788-
}
2789-
chars= 128; // Marker that chars existed
2790-
}
2791-
}
2792-
sort= (sort << 8) + (wild_pos ? MY_MIN(wild_pos, 127U) : chars);
2793-
}
2794-
va_end(args);
2795-
return sort;
2796-
}
2797-
2798-
27992762
static int acl_compare(const ACL_ACCESS *a, const ACL_ACCESS *b)
28002763
{
28012764
if (a->sort > b->sort)
@@ -3157,7 +3120,7 @@ ACL_USER::ACL_USER(THD *thd, const LEX_USER &combo,
31573120
user= safe_lexcstrdup_root(&acl_memroot, combo.user);
31583121
update_hostname(&host, safe_strdup_root(&acl_memroot, combo.host.str));
31593122
hostname_length= combo.host.length;
3160-
sort= get_sort(2, host.hostname, user.str);
3123+
sort= get_magic_sort("hu", host.hostname, user.str);
31613124
password_last_changed= thd->query_start();
31623125
password_lifetime= -1;
31633126
my_init_dynamic_array(&role_grants, sizeof(ACL_USER *), 0, 8, MYF(0));
@@ -3314,7 +3277,7 @@ static void acl_insert_db(const char *user, const char *host, const char *db,
33143277
update_hostname(&acl_db.host, safe_strdup_root(&acl_memroot, host));
33153278
acl_db.db=strdup_root(&acl_memroot,db);
33163279
acl_db.initial_access= acl_db.access= privileges;
3317-
acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
3280+
acl_db.sort=get_magic_sort("hdu", acl_db.host.hostname, acl_db.db, acl_db.user);
33183281
acl_dbs.push(acl_db);
33193282
rebuild_acl_dbs();
33203283
}
@@ -5033,7 +4996,7 @@ class GRANT_NAME :public Sql_alloc
50334996
char *db, *user, *tname, *hash_key;
50344997
ulong privs;
50354998
ulong init_privs; /* privileges found in physical table */
5036-
ulong sort;
4999+
ulonglong sort;
50375000
size_t key_length;
50385001
GRANT_NAME(const char *h, const char *d,const char *u,
50395002
const char *t, ulong p, bool is_routine);
@@ -5079,7 +5042,7 @@ void GRANT_NAME::set_user_details(const char *h, const char *d,
50795042
my_casedn_str(files_charset_info, db);
50805043
}
50815044
user = strdup_root(&grant_memroot,u);
5082-
sort= get_sort(3,host.hostname,db,user);
5045+
sort= get_magic_sort("hdu", host.hostname, db, user);
50835046
if (tname != t)
50845047
{
50855048
tname= strdup_root(&grant_memroot, t);
@@ -5121,7 +5084,7 @@ GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine)
51215084
update_hostname(&host, hostname);
51225085

51235086
db= get_field(&grant_memroot,form->field[1]);
5124-
sort= get_sort(3, host.hostname, db, user);
5087+
sort= get_magic_sort("hdu", host.hostname, db, user);
51255088
tname= get_field(&grant_memroot,form->field[3]);
51265089
if (!db || !tname)
51275090
{
@@ -6214,7 +6177,7 @@ static int update_role_db(int merged, int first, ulong access,
62146177
acl_db.db= acl_dbs.at(first).db;
62156178
acl_db.access= access;
62166179
acl_db.initial_access= 0;
6217-
acl_db.sort=get_sort(3, "", acl_db.db, role);
6180+
acl_db.sort= get_magic_sort("hdu", "", acl_db.db, role);
62186181
acl_dbs.push(acl_db);
62196182
return 2;
62206183
}

0 commit comments

Comments
 (0)