Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

executor: fix inconsistent of grants privileges with MySQL when executing grant all on ... (#12330) #13943

Merged
merged 5 commits into from
Dec 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions executor/grant.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@ func (e *GrantExec) grantColumnPriv(priv *ast.PrivElem, user *ast.UserSpec) erro
func composeGlobalPrivUpdate(priv mysql.PrivilegeType, value string) (string, error) {
if priv == mysql.AllPriv {
strs := make([]string, 0, len(mysql.Priv2UserCol))
for _, v := range mysql.Priv2UserCol {
strs = append(strs, fmt.Sprintf(`%s='%s'`, v, value))
for _, v := range mysql.AllGlobalPrivs {
strs = append(strs, fmt.Sprintf(`%s='%s'`, mysql.Priv2UserCol[v], value))
}
return strings.Join(strs, ", "), nil
}
Expand Down
41 changes: 40 additions & 1 deletion executor/grant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package executor_test

import (
"bytes"
"fmt"
"strings"

Expand Down Expand Up @@ -53,6 +54,12 @@ func (s *testSuite3) TestGrantGlobal(c *C) {
sql := fmt.Sprintf("SELECT %s FROM mysql.User WHERE User=\"testGlobal1\" and host=\"localhost\"", mysql.Priv2UserCol[v])
tk.MustQuery(sql).Check(testkit.Rows("Y"))
}
//with grant option
tk.MustExec("GRANT ALL ON *.* TO 'testGlobal1'@'localhost' WITH GRANT OPTION;")
for _, v := range mysql.AllGlobalPrivs {
sql := fmt.Sprintf("SELECT %s FROM mysql.User WHERE User=\"testGlobal1\" and host=\"localhost\"", mysql.Priv2UserCol[v])
tk.MustQuery(sql).Check(testkit.Rows("Y"))
}
}

func (s *testSuite3) TestGrantDBScope(c *C) {
Expand Down Expand Up @@ -96,6 +103,13 @@ func (s *testSuite3) TestWithGrantOption(c *C) {
// Grant select priv to the user, with grant option.
tk.MustExec("GRANT select ON test.* TO 'testWithGrant'@'localhost' WITH GRANT OPTION;")
tk.MustQuery("SELECT grant_priv FROM mysql.DB WHERE User=\"testWithGrant\" and host=\"localhost\" and db=\"test\"").Check(testkit.Rows("Y"))

tk.MustExec("CREATE USER 'testWithGrant1'")
tk.MustQuery("SELECT grant_priv FROM mysql.user WHERE User=\"testWithGrant1\"").Check(testkit.Rows("N"))
tk.MustExec("GRANT ALL ON *.* TO 'testWithGrant1'")
tk.MustQuery("SELECT grant_priv FROM mysql.user WHERE User=\"testWithGrant1\"").Check(testkit.Rows("N"))
tk.MustExec("GRANT ALL ON *.* TO 'testWithGrant1' WITH GRANT OPTION")
tk.MustQuery("SELECT grant_priv FROM mysql.user WHERE User=\"testWithGrant1\"").Check(testkit.Rows("Y"))
}

func (s *testSuite3) TestTableScope(c *C) {
Expand Down Expand Up @@ -124,7 +138,7 @@ func (s *testSuite3) TestTableScope(c *C) {
tk.MustExec("USE test;")
tk.MustExec(`CREATE TABLE test2(c1 int);`)
// Grant all table scope privs.
tk.MustExec("GRANT ALL ON test2 TO 'testTbl1'@'localhost';")
tk.MustExec("GRANT ALL ON test2 TO 'testTbl1'@'localhost' WITH GRANT OPTION;")
// Make sure all the table privs for granted user are in the Table_priv set.
for _, v := range mysql.AllTablePrivs {
rows := tk.MustQuery(`SELECT Table_priv FROM mysql.Tables_priv WHERE User="testTbl1" and host="localhost" and db="test" and Table_name="test2";`).Rows()
Expand Down Expand Up @@ -224,3 +238,28 @@ func (s *testSuite3) TestGrantUnderANSIQuotes(c *C) {
tk.MustExec(`REVOKE ALL PRIVILEGES ON video_ulimit.* FROM web@'%';`)
tk.MustExec(`DROP USER IF EXISTS 'web'@'%'`)
}

func (s *testSuite3) TestUserTableConsistency(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("create user superadmin")
tk.MustExec("grant all privileges on *.* to 'superadmin'")

// GrantPriv is not in AllGlobalPrivs any more, see pingcap/parser#581
c.Assert(len(mysql.Priv2UserCol), Equals, len(mysql.AllGlobalPrivs)+1)

var buf bytes.Buffer
var res bytes.Buffer
buf.WriteString("select ")
i := 0
for _, priv := range mysql.AllGlobalPrivs {
if i != 0 {
buf.WriteString(", ")
res.WriteString(" ")
}
buf.WriteString(mysql.Priv2UserCol[priv])
res.WriteString("Y")
i++
}
buf.WriteString(" from mysql.user where user = 'superadmin'")
tk.MustQuery(buf.String()).Check(testkit.Rows(res.String()))
}
2 changes: 1 addition & 1 deletion executor/revoke_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (s *testSuite1) TestRevokeTableScope(c *C) {

// Make sure all the table privs for new user is Y.
res := tk.MustQuery(`SELECT Table_priv FROM mysql.tables_priv WHERE User="testTblRevoke" and host="localhost" and db="test" and Table_name="test1"`)
res.Check(testkit.Rows("Select,Insert,Update,Delete,Create,Drop,Grant,Index,Alter"))
res.Check(testkit.Rows("Select,Insert,Update,Delete,Create,Drop,Index,Alter"))

// Revoke each priv from the user.
for _, v := range mysql.AllTablePrivs {
Expand Down
7 changes: 4 additions & 3 deletions executor/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,10 +286,11 @@ func (s *testSuite2) TestShow2(c *C) {
tk.MustQuery("show databases like 'test'").Check(testkit.Rows("test"))

tk.MustExec(`grant all on *.* to 'root'@'%'`)
tk.MustQuery("show grants").Check(testkit.Rows(`GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'`))

tk.MustQuery("show grants for current_user()").Check(testkit.Rows(`GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'`))
tk.MustQuery("show grants for current_user").Check(testkit.Rows(`GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'`))
tk.MustQuery("show grants").Check(testkit.Rows(`GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION`))

tk.MustQuery("show grants for current_user()").Check(testkit.Rows(`GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION`))
tk.MustQuery("show grants for current_user").Check(testkit.Rows(`GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION`))
}

func (s *testSuite2) TestShowCreateUser(c *C) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ require (
github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e
github.com/pingcap/kvproto v0.0.0-20191106014506-c5d88d699a8d
github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd
github.com/pingcap/parser v0.0.0-20191205094455-91f36bd4dbcc
github.com/pingcap/parser v0.0.0-20191209061101-9504797d375e
github.com/pingcap/pd v1.1.0-beta.0.20190912093418-dc03c839debd
github.com/pingcap/tidb-tools v3.0.6-0.20191119150227-ff0a3c6e5763+incompatible
github.com/pingcap/tipb v0.0.0-20191120045257-1b9900292ab6
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ github.com/pingcap/kvproto v0.0.0-20191106014506-c5d88d699a8d h1:zTHgLr8+0LTEJmj
github.com/pingcap/kvproto v0.0.0-20191106014506-c5d88d699a8d/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY=
github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd h1:hWDol43WY5PGhsh3+8794bFHY1bPrmu6bTalpssCrGg=
github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw=
github.com/pingcap/parser v0.0.0-20191205094455-91f36bd4dbcc h1:xlLnj8xnQPR84gxR9a1G+7E5T9MSXGk62DQasfBQ1wY=
github.com/pingcap/parser v0.0.0-20191205094455-91f36bd4dbcc/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/parser v0.0.0-20191209061101-9504797d375e h1:o7gGWvwtOmGYEH1vY5WkyXurch3ji9iTiLWtmpTvgrk=
github.com/pingcap/parser v0.0.0-20191209061101-9504797d375e/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/pd v1.1.0-beta.0.20190912093418-dc03c839debd h1:bKj6hodu/ro78B0oN2yicdGn0t4yd9XjnyoW95qmWic=
github.com/pingcap/pd v1.1.0-beta.0.20190912093418-dc03c839debd/go.mod h1:I7TEby5BHTYIxgHszfsOJSBsk8b2Qt8QrSIgdv5n5QQ=
github.com/pingcap/tidb-tools v3.0.6-0.20191119150227-ff0a3c6e5763+incompatible h1:I8HirWsu1MZp6t9G/g8yKCEjJJxtHooKakEgccvdJ4M=
Expand Down
86 changes: 79 additions & 7 deletions privilege/privileges/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -758,29 +758,52 @@ func (p *MySQLPrivilege) showGrants(user, host string, roles []*auth.RoleIdentit
allRoles := p.FindAllRole(roles)
// Show global grants.
var currentPriv mysql.PrivilegeType
var hasGrantOptionPriv bool = false
var g string
for _, record := range p.User {
if record.User == user && record.Host == host {
hasGlobalGrant = true
if (record.Privileges & mysql.GrantPriv) > 0 {
hasGrantOptionPriv = true
currentPriv |= (record.Privileges & ^mysql.GrantPriv)
continue
}
currentPriv |= record.Privileges
} else {
for _, r := range allRoles {
if record.User == r.Username && record.Host == r.Hostname {
hasGlobalGrant = true
if (record.Privileges & mysql.GrantPriv) > 0 {
hasGrantOptionPriv = true
currentPriv |= (record.Privileges & ^mysql.GrantPriv)
continue
}
currentPriv |= record.Privileges
}
}
}
}
g = userPrivToString(currentPriv)
if len(g) > 0 {
s := fmt.Sprintf(`GRANT %s ON *.* TO '%s'@'%s'`, g, user, host)
var s string
if hasGrantOptionPriv {
s = fmt.Sprintf(`GRANT %s ON *.* TO '%s'@'%s' WITH GRANT OPTION`, g, user, host)

} else {
s = fmt.Sprintf(`GRANT %s ON *.* TO '%s'@'%s'`, g, user, host)

}
gs = append(gs, s)
}

// This is a mysql convention.
if len(gs) == 0 && hasGlobalGrant {
s := fmt.Sprintf("GRANT USAGE ON *.* TO '%s'@'%s'", user, host)
var s string
if hasGrantOptionPriv {
s = fmt.Sprintf("GRANT USAGE ON *.* TO '%s'@'%s' WITH GRANT OPTION", user, host)
} else {
s = fmt.Sprintf("GRANT USAGE ON *.* TO '%s'@'%s'", user, host)
}
gs = append(gs, s)
}

Expand All @@ -789,16 +812,36 @@ func (p *MySQLPrivilege) showGrants(user, host string, roles []*auth.RoleIdentit
for _, record := range p.DB {
if record.User == user && record.Host == host {
if _, ok := dbPrivTable[record.DB]; ok {
if (record.Privileges & mysql.GrantPriv) > 0 {
hasGrantOptionPriv = true
dbPrivTable[record.DB] |= (record.Privileges & ^mysql.GrantPriv)
continue
}
dbPrivTable[record.DB] |= record.Privileges
} else {
if (record.Privileges & mysql.GrantPriv) > 0 {
hasGrantOptionPriv = true
dbPrivTable[record.DB] = (record.Privileges & ^mysql.GrantPriv)
continue
}
dbPrivTable[record.DB] = record.Privileges
}
} else {
for _, r := range allRoles {
if record.User == r.Username && record.Host == r.Hostname {
if _, ok := dbPrivTable[record.DB]; ok {
if (record.Privileges & mysql.GrantPriv) > 0 {
hasGrantOptionPriv = true
dbPrivTable[record.DB] |= (record.Privileges & ^mysql.GrantPriv)
continue
}
dbPrivTable[record.DB] |= record.Privileges
} else {
if (record.Privileges & mysql.GrantPriv) > 0 {
hasGrantOptionPriv = true
dbPrivTable[record.DB] = (record.Privileges & ^mysql.GrantPriv)
continue
}
dbPrivTable[record.DB] = record.Privileges
}
}
Expand All @@ -808,7 +851,14 @@ func (p *MySQLPrivilege) showGrants(user, host string, roles []*auth.RoleIdentit
for dbName, priv := range dbPrivTable {
g := dbPrivToString(priv)
if len(g) > 0 {
s := fmt.Sprintf(`GRANT %s ON %s.* TO '%s'@'%s'`, g, dbName, user, host)
var s string
if hasGrantOptionPriv {
s = fmt.Sprintf(`GRANT %s ON %s.* TO '%s'@'%s' WITH GRANT OPTION`, g, dbName, user, host)

} else {
s = fmt.Sprintf(`GRANT %s ON %s.* TO '%s'@'%s'`, g, dbName, user, host)

}
gs = append(gs, s)
}
}
Expand All @@ -819,16 +869,36 @@ func (p *MySQLPrivilege) showGrants(user, host string, roles []*auth.RoleIdentit
recordKey := record.DB + "." + record.TableName
if record.User == user && record.Host == host {
if _, ok := dbPrivTable[record.DB]; ok {
if (record.TablePriv & mysql.GrantPriv) > 0 {
hasGrantOptionPriv = true
tablePrivTable[recordKey] |= (record.TablePriv & ^mysql.GrantPriv)
continue
}
tablePrivTable[recordKey] |= record.TablePriv
} else {
if (record.TablePriv & mysql.GrantPriv) > 0 {
hasGrantOptionPriv = true
tablePrivTable[recordKey] = (record.TablePriv & ^mysql.GrantPriv)
continue
}
tablePrivTable[recordKey] = record.TablePriv
}
} else {
for _, r := range allRoles {
if record.User == r.Username && record.Host == r.Hostname {
if _, ok := dbPrivTable[record.DB]; ok {
if (record.TablePriv & mysql.GrantPriv) > 0 {
hasGrantOptionPriv = true
tablePrivTable[recordKey] |= (record.TablePriv & ^mysql.GrantPriv)
continue
}
tablePrivTable[recordKey] |= record.TablePriv
} else {
if (record.TablePriv & mysql.GrantPriv) > 0 {
hasGrantOptionPriv = true
tablePrivTable[recordKey] = (record.TablePriv & ^mysql.GrantPriv)
continue
}
tablePrivTable[recordKey] = record.TablePriv
}
}
Expand All @@ -838,7 +908,12 @@ func (p *MySQLPrivilege) showGrants(user, host string, roles []*auth.RoleIdentit
for k, priv := range tablePrivTable {
g := tablePrivToString(priv)
if len(g) > 0 {
s := fmt.Sprintf(`GRANT %s ON %s TO '%s'@'%s'`, g, k, user, host)
var s string
if hasGrantOptionPriv {
s = fmt.Sprintf(`GRANT %s ON %s TO '%s'@'%s' WITH GRANT OPTION`, g, k, user, host)
} else {
s = fmt.Sprintf(`GRANT %s ON %s TO '%s'@'%s'`, g, k, user, host)
}
gs = append(gs, s)
}
}
Expand Down Expand Up @@ -920,9 +995,6 @@ func appendUserPrivilegesTableRow(rows [][]types.Datum, user UserRecord) [][]typ
guarantee := fmt.Sprintf("'%s'@'%s'", user.User, user.Host)

for _, priv := range mysql.AllGlobalPrivs {
if priv == mysql.GrantPriv {
continue
}
if user.Privileges&priv > 0 {
privilegeType := mysql.Priv2Str[priv]
// +---------------------------+---------------+-------------------------+--------------+
Expand Down
26 changes: 24 additions & 2 deletions privilege/privileges/privileges_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,20 @@ func (s *testPrivilegeSuite) TestShowGrants(c *C) {
c.Assert(gs, HasLen, 1)
c.Assert(gs[0], Equals, `GRANT ALL PRIVILEGES ON *.* TO 'show'@'localhost'`)

// All privileges with grant option
mustExec(c, se, `GRANT ALL ON *.* TO 'show'@'localhost' WITH GRANT OPTION;`)
gs, err = pc.ShowGrants(se, &auth.UserIdentity{Username: "show", Hostname: "localhost"}, nil)
c.Assert(err, IsNil)
c.Assert(gs, HasLen, 1)
c.Assert(gs[0], Equals, `GRANT ALL PRIVILEGES ON *.* TO 'show'@'localhost' WITH GRANT OPTION`)

// Revoke grant option
mustExec(c, se, `REVOKE GRANT OPTION ON *.* FROM 'show'@'localhost';`)
gs, err = pc.ShowGrants(se, &auth.UserIdentity{Username: "show", Hostname: "localhost"}, nil)
c.Assert(err, IsNil)
c.Assert(gs, HasLen, 1)
c.Assert(gs[0], Equals, `GRANT ALL PRIVILEGES ON *.* TO 'show'@'localhost'`)

// Add db scope privileges
mustExec(c, se, `GRANT Select ON test.* TO 'show'@'localhost';`)
gs, err = pc.ShowGrants(se, &auth.UserIdentity{Username: "show", Hostname: "localhost"}, nil)
Expand Down Expand Up @@ -490,6 +504,14 @@ func (s *testPrivilegeSuite) TestUseDB(c *C) {
mustExec(c, se, "CREATE USER 'usesuper'")
mustExec(c, se, "CREATE USER 'usenobody'")
mustExec(c, se, "GRANT ALL ON *.* TO 'usesuper'")
//without grant option
c.Assert(se.Auth(&auth.UserIdentity{Username: "usesuper", Hostname: "localhost", AuthUsername: "usesuper", AuthHostname: "%"}, nil, nil), IsTrue)
_, e := se.Execute(context.Background(), "GRANT SELECT ON mysql.* TO 'usenobody'")
c.Assert(e, NotNil)
//with grant option
se = newSession(c, s.store, s.dbName)
// high privileged user
mustExec(c, se, "GRANT ALL ON *.* TO 'usesuper' WITH GRANT OPTION")
c.Assert(se.Auth(&auth.UserIdentity{Username: "usesuper", Hostname: "localhost", AuthUsername: "usesuper", AuthHostname: "%"}, nil, nil), IsTrue)
mustExec(c, se, "use mysql")
// low privileged user
Expand Down Expand Up @@ -536,7 +558,7 @@ func (s *testPrivilegeSuite) TestSetGlobal(c *C) {
func (s *testPrivilegeSuite) TestCreateDropUser(c *C) {
se := newSession(c, s.store, s.dbName)
mustExec(c, se, `CREATE USER tcd1, tcd2`)
mustExec(c, se, `GRANT ALL ON *.* to tcd2`)
mustExec(c, se, `GRANT ALL ON *.* to tcd2 WITH GRANT OPTION`)

// should fail
c.Assert(se.Auth(&auth.UserIdentity{Username: "tcd1", Hostname: "localhost", AuthUsername: "tcd1", AuthHostname: "%"}, nil, nil), IsTrue)
Expand Down Expand Up @@ -579,7 +601,7 @@ func (s *testPrivilegeSuite) TestAnalyzeTable(c *C) {
// high privileged user
mustExec(c, se, "CREATE USER 'asuper'")
mustExec(c, se, "CREATE USER 'anobody'")
mustExec(c, se, "GRANT ALL ON *.* TO 'asuper'")
mustExec(c, se, "GRANT ALL ON *.* TO 'asuper' WITH GRANT OPTION")
mustExec(c, se, "CREATE DATABASE atest")
mustExec(c, se, "use atest")
mustExec(c, se, "CREATE TABLE t1 (a int)")
Expand Down