diff --git a/executor/grant.go b/executor/grant.go index 8f713dbddcaf9..66157d591b9b3 100644 --- a/executor/grant.go +++ b/executor/grant.go @@ -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 } diff --git a/executor/grant_test.go b/executor/grant_test.go index 0016e0b96c6f1..f652ec37a1448 100644 --- a/executor/grant_test.go +++ b/executor/grant_test.go @@ -53,6 +53,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) { @@ -96,6 +102,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) { @@ -124,7 +137,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() diff --git a/executor/show_test.go b/executor/show_test.go index e8a5256763453..32d4d946be956 100644 --- a/executor/show_test.go +++ b/executor/show_test.go @@ -285,12 +285,11 @@ func (s *testSuite2) TestShow2(c *C) { tk.MustQuery("show databases like 'test'").Check(testkit.Rows("test")) - AllPrivs := "Select,Insert,Update,Delete,Create,Drop,Process,References,Alter,Show Databases,Super,Execute,Index,Create User,Trigger,Create View,Show View,Create Role,Drop Role,CREATE TEMPORARY TABLES,LOCK TABLES,CREATE ROUTINE,ALTER ROUTINE,EVENT,SHUTDOWN" tk.MustExec(`grant all on *.* to 'root'@'%'`) - tk.MustQuery("show grants").Check(testkit.Rows(`GRANT ` + AllPrivs + ` 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 ` + AllPrivs + ` ON *.* TO 'root'@'%'`)) - tk.MustQuery("show grants for current_user").Check(testkit.Rows(`GRANT ` + AllPrivs + ` ON *.* TO 'root'@'%'`)) + 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) { diff --git a/go.sum b/go.sum index e0aa5d371ee9c..1b011443ef80f 100644 --- a/go.sum +++ b/go.sum @@ -12,7 +12,6 @@ github.com/blacktear23/go-proxyprotocol v0.0.0-20180807104634-af7a81e8dd0d/go.mo github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20171208011716-f6d7a1f6fbf3/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= @@ -62,13 +61,11 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff h1:kOkM9whyQYodu09SJ6W3NCsHG7crFaJILQ22Gozp3lg= github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v0.0.0-20180814211427-aa810b61a9c7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -162,7 +159,6 @@ github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17Xtb github.com/pingcap/kvproto v0.0.0-20190822090350-11ea838aedf7/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY= github.com/pingcap/kvproto v0.0.0-20190910074005-0e61b6f435c1 h1:DNvxkdcjA0TBIIIF+K2w9KMlTzMZzLZ5JVF26kTCPhg= github.com/pingcap/kvproto v0.0.0-20190910074005-0e61b6f435c1/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/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww9rkZ1DnWfl0pXV3BOWlkYIjA= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= @@ -249,20 +245,16 @@ go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20190320044326-77d4b742cdbf h1:rmttwKPEgG/l4UscTDYtaJgeUsedKPKSyFfNQLI6q+I= go.etcd.io/etcd v0.0.0-20190320044326-77d4b742cdbf/go.mod h1:KSGwdbiFchh5KIC9My2+ZVl5/3ANcwohw50dpPwa2cw= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.2.0 h1:6I+W7f5VwC5SV9dNrZ3qXrDB9mD0dyGOi/ZJmYw03T4= go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180608092829-8ac0e0d97ce4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -285,7 +277,6 @@ golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -296,11 +287,9 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190909082730-f460065e899a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b h1:3S2h5FadpNr0zUUCVZjlKIEYF+KaX/OBplTGo89CYHI= golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2IVY3KZs6p9mix0ziNYJM= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -328,7 +317,6 @@ gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4 gopkg.in/alecthomas/gometalinter.v2 v2.0.12/go.mod h1:NDRytsqEZyolNuAgTzJkZMkSQM7FIKyzVzGhjB/qfYo= gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c/go.mod h1:3HH7i1SgMqlzxCcBmUHW657sD4Kvv9sC3HpL3YukzwA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/privilege/privileges/cache.go b/privilege/privileges/cache.go index 284db28e05762..f82f50e7dbbed 100644 --- a/privilege/privileges/cache.go +++ b/privilege/privileges/cache.go @@ -763,15 +763,26 @@ 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 } } @@ -779,13 +790,25 @@ func (p *MySQLPrivilege) showGrants(user, host string, roles []*auth.RoleIdentit } 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) } @@ -794,16 +817,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 } } @@ -813,7 +856,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) } } @@ -824,16 +874,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 } } @@ -843,7 +913,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) } } @@ -925,9 +1000,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] // +---------------------------+---------------+-------------------------+--------------+ diff --git a/privilege/privileges/privileges_test.go b/privilege/privileges/privileges_test.go index bfff0fd7c52fc..b5b843c38014e 100644 --- a/privilege/privileges/privileges_test.go +++ b/privilege/privileges/privileges_test.go @@ -258,19 +258,32 @@ func (s *testPrivilegeSuite) TestShowGrants(c *C) { c.Assert(gs[0], Equals, `GRANT Select,Update,Index ON *.* TO 'show'@'localhost'`) // All privileges - AllPrivs := "Select,Insert,Update,Delete,Create,Drop,Process,References,Alter,Show Databases,Super,Execute,Index,Create User,Trigger,Create View,Show View,Create Role,Drop Role,CREATE TEMPORARY TABLES,LOCK TABLES,CREATE ROUTINE,ALTER ROUTINE,EVENT,SHUTDOWN" mustExec(c, se, `GRANT ALL ON *.* TO '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 `+AllPrivs+` ON *.* TO 'show'@'localhost'`) + 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) c.Assert(err, IsNil) c.Assert(gs, HasLen, 2) - expected := []string{`GRANT ` + AllPrivs + ` ON *.* TO 'show'@'localhost'`, + expected := []string{`GRANT ALL PRIVILEGES ON *.* TO 'show'@'localhost'`, `GRANT Select ON test.* TO 'show'@'localhost'`} c.Assert(testutil.CompareUnorderedStringSlice(gs, expected), IsTrue) @@ -278,7 +291,7 @@ func (s *testPrivilegeSuite) TestShowGrants(c *C) { gs, err = pc.ShowGrants(se, &auth.UserIdentity{Username: "show", Hostname: "localhost"}, nil) c.Assert(err, IsNil) c.Assert(gs, HasLen, 3) - expected = []string{`GRANT ` + AllPrivs + ` ON *.* TO 'show'@'localhost'`, + expected = []string{`GRANT ALL PRIVILEGES ON *.* TO 'show'@'localhost'`, `GRANT Select ON test.* TO 'show'@'localhost'`, `GRANT Index ON test1.* TO 'show'@'localhost'`} c.Assert(testutil.CompareUnorderedStringSlice(gs, expected), IsTrue) @@ -287,7 +300,7 @@ func (s *testPrivilegeSuite) TestShowGrants(c *C) { gs, err = pc.ShowGrants(se, &auth.UserIdentity{Username: "show", Hostname: "localhost"}, nil) c.Assert(err, IsNil) c.Assert(gs, HasLen, 3) - expected = []string{`GRANT ` + AllPrivs + ` ON *.* TO 'show'@'localhost'`, + expected = []string{`GRANT ALL PRIVILEGES ON *.* TO 'show'@'localhost'`, `GRANT Select ON test.* TO 'show'@'localhost'`, `GRANT ALL PRIVILEGES ON test1.* TO 'show'@'localhost'`} c.Assert(testutil.CompareUnorderedStringSlice(gs, expected), IsTrue) @@ -297,7 +310,7 @@ func (s *testPrivilegeSuite) TestShowGrants(c *C) { gs, err = pc.ShowGrants(se, &auth.UserIdentity{Username: "show", Hostname: "localhost"}, nil) c.Assert(err, IsNil) c.Assert(gs, HasLen, 4) - expected = []string{`GRANT ` + AllPrivs + ` ON *.* TO 'show'@'localhost'`, + expected = []string{`GRANT ALL PRIVILEGES ON *.* TO 'show'@'localhost'`, `GRANT Select ON test.* TO 'show'@'localhost'`, `GRANT ALL PRIVILEGES ON test1.* TO 'show'@'localhost'`, `GRANT Update ON test.test TO 'show'@'localhost'`} @@ -493,6 +506,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 @@ -539,7 +560,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) @@ -582,7 +603,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)") @@ -683,12 +704,12 @@ func (s *testPrivilegeSuite) TestUserTableConsistency(c *C) { var res bytes.Buffer buf.WriteString("select ") i := 0 - for _, priv := range mysql.Priv2UserCol { + for _, priv := range mysql.AllGlobalPrivs { if i != 0 { buf.WriteString(", ") res.WriteString(" ") } - buf.WriteString(priv) + buf.WriteString(mysql.Priv2UserCol[priv]) res.WriteString("Y") i++ }